aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs1987
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs2311
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs683
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs554
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs27
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs64
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs17
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs12
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1264
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs104
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs439
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs113
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs203
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs590
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs815
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs366
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1255
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs153
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs182
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs1047
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs558
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs183
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs55
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs314
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs287
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs1015
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs269
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt346
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs150
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs56
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs95
33 files changed, 11905 insertions, 3621 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
new file mode 100755
index 0000000..77ea3ed
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -0,0 +1,1987 @@
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 if (m_paramsHandle.IsAllocated)
217 {
218 m_paramsHandle.Free();
219 }
220 if (m_collisionArrayPinnedHandle.IsAllocated)
221 {
222 m_collisionArrayPinnedHandle.Free();
223 }
224 if (m_updateArrayPinnedHandle.IsAllocated)
225 {
226 m_updateArrayPinnedHandle.Free();
227 }
228}
229
230public override bool PushUpdate(BulletBody obj)
231{
232 BulletBodyUnman bodyu = obj as BulletBodyUnman;
233 return BSAPICPP.PushUpdate2(bodyu.ptr);
234}
235
236public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value)
237{
238 BulletWorldUnman worldu = world as BulletWorldUnman;
239 return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value);
240}
241
242// =====================================================================================
243// Mesh, hull, shape and body creation helper routines
244public override BulletShape CreateMeshShape(BulletWorld world,
245 int indicesCount, int[] indices,
246 int verticesCount, float[] vertices)
247{
248 BulletWorldUnman worldu = world as BulletWorldUnman;
249 return new BulletShapeUnman(
250 BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
251 BSPhysicsShapeType.SHAPE_MESH);
252}
253
254public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
255{
256 BulletWorldUnman worldu = world as BulletWorldUnman;
257 return new BulletShapeUnman(
258 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
259 BSPhysicsShapeType.SHAPE_HULL);
260}
261
262public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
263{
264 BulletWorldUnman worldu = world as BulletWorldUnman;
265 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
266 return new BulletShapeUnman(
267 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
268 BSPhysicsShapeType.SHAPE_HULL);
269}
270
271public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
272{
273 BulletWorldUnman worldu = world as BulletWorldUnman;
274 return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type);
275}
276
277public override bool IsNativeShape(BulletShape shape)
278{
279 BulletShapeUnman shapeu = shape as BulletShapeUnman;
280 if (shapeu != null && shapeu.HasPhysicalShape)
281 return BSAPICPP.IsNativeShape2(shapeu.ptr);
282 return false;
283}
284
285public override void SetShapeCollisionMargin(BulletShape shape, float margin)
286{
287 BulletShapeUnman shapeu = shape as BulletShapeUnman;
288 if (shapeu != null && shapeu.HasPhysicalShape)
289 BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
290}
291
292public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
293{
294 BulletWorldUnman worldu = world as BulletWorldUnman;
295 return new BulletShapeUnman(
296 BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale),
297 BSPhysicsShapeType.SHAPE_CAPSULE);
298}
299
300public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree)
301{
302 BulletWorldUnman worldu = world as BulletWorldUnman;
303 return new BulletShapeUnman(
304 BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree),
305 BSPhysicsShapeType.SHAPE_COMPOUND);
306
307}
308
309public override int GetNumberOfCompoundChildren(BulletShape shape)
310{
311 BulletShapeUnman shapeu = shape as BulletShapeUnman;
312 if (shapeu != null && shapeu.HasPhysicalShape)
313 return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr);
314 return 0;
315}
316
317public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot)
318{
319 BulletShapeUnman shapeu = shape as BulletShapeUnman;
320 BulletShapeUnman addShapeu = addShape as BulletShapeUnman;
321 BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot);
322}
323
324public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
325{
326 BulletShapeUnman shapeu = shape as BulletShapeUnman;
327 return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
328}
329
330public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
331{
332 BulletShapeUnman shapeu = shape as BulletShapeUnman;
333 return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
334}
335
336public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape)
337{
338 BulletShapeUnman shapeu = shape as BulletShapeUnman;
339 BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman;
340 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
341}
342
343public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb)
344{
345 BulletShapeUnman shapeu = pShape as BulletShapeUnman;
346 BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb);
347}
348
349public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
350{
351 BulletShapeUnman shapeu = shape as BulletShapeUnman;
352 BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr);
353}
354
355public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id)
356{
357 BulletWorldUnman worldu = world as BulletWorldUnman;
358 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
359 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type);
360}
361
362public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
363{
364 BulletWorldUnman worldu = world as BulletWorldUnman;
365 BulletShapeUnman shapeu = shape as BulletShapeUnman;
366 return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr);
367}
368
369public override CollisionObjectTypes GetBodyType(BulletBody obj)
370{
371 BulletBodyUnman bodyu = obj as BulletBodyUnman;
372 return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr);
373}
374
375public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
376{
377 BulletWorldUnman worldu = world as BulletWorldUnman;
378 BulletShapeUnman shapeu = shape as BulletShapeUnman;
379 return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
380}
381
382public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot)
383{
384 BulletShapeUnman shapeu = shape as BulletShapeUnman;
385 return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot));
386}
387
388public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
389{
390 BulletWorldUnman worldu = world as BulletWorldUnman;
391 BulletShapeUnman shapeu = shape as BulletShapeUnman;
392 return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
393}
394
395public override void DestroyObject(BulletWorld world, BulletBody obj)
396{
397 BulletWorldUnman worldu = world as BulletWorldUnman;
398 BulletBodyUnman bodyu = obj as BulletBodyUnman;
399 BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr);
400}
401
402// =====================================================================================
403// Terrain creation and helper routines
404public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin)
405{
406 return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE);
407}
408
409public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
410 float scaleFactor, float collisionMargin)
411{
412 return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin),
413 BSPhysicsShapeType.SHAPE_TERRAIN);
414}
415
416// =====================================================================================
417// Constraint creation and helper routines
418public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
419 Vector3 frame1loc, Quaternion frame1rot,
420 Vector3 frame2loc, Quaternion frame2rot,
421 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
422{
423 BulletWorldUnman worldu = world as BulletWorldUnman;
424 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
425 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
426 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
427 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
428}
429
430public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
431 Vector3 joinPoint,
432 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
433{
434 BulletWorldUnman worldu = world as BulletWorldUnman;
435 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
436 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
437 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
438 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
439}
440
441public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
442 Vector3 frameInBloc, Quaternion frameInBrot,
443 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
444{
445 BulletWorldUnman worldu = world as BulletWorldUnman;
446 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
447 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr,
448 frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies));
449}
450
451public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
452 Vector3 frame1loc, Quaternion frame1rot,
453 Vector3 frame2loc, Quaternion frame2rot,
454 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
455{
456 BulletWorldUnman worldu = world as BulletWorldUnman;
457 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
458 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
459 return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
460 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
461}
462
463public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
464 Vector3 pivotinA, Vector3 pivotinB,
465 Vector3 axisInA, Vector3 axisInB,
466 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
467{
468 BulletWorldUnman worldu = world as BulletWorldUnman;
469 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
470 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
471 return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
472 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
473}
474
475public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
476 Vector3 frame1loc, Quaternion frame1rot,
477 Vector3 frame2loc, Quaternion frame2rot,
478 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
479{
480 BulletWorldUnman worldu = world as BulletWorldUnman;
481 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
482 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
483 return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
484 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
485}
486
487public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
488 Vector3 frame1loc, Quaternion frame1rot,
489 Vector3 frame2loc, Quaternion frame2rot,
490 bool disableCollisionsBetweenLinkedBodies)
491{
492 BulletWorldUnman worldu = world as BulletWorldUnman;
493 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
494 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
495 return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
496 frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies));
497}
498
499public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
500 Vector3 axisInA, Vector3 axisInB,
501 float ratio, bool disableCollisionsBetweenLinkedBodies)
502{
503 BulletWorldUnman worldu = world as BulletWorldUnman;
504 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
505 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
506 return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB,
507 ratio, disableCollisionsBetweenLinkedBodies));
508}
509
510public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
511 Vector3 pivotInA, Vector3 pivotInB,
512 bool disableCollisionsBetweenLinkedBodies)
513{
514 BulletWorldUnman worldu = world as BulletWorldUnman;
515 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
516 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
517 return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB,
518 disableCollisionsBetweenLinkedBodies));
519}
520
521public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
522{
523 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
524 BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
525}
526
527public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
528{
529 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
530 BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
531}
532
533public override bool SetFrames(BulletConstraint constrain,
534 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
535{
536 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
537 return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
538}
539
540public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
541{
542 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
543 return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
544}
545
546public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
547{
548 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
549 return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
550}
551
552public override bool UseFrameOffset(BulletConstraint constrain, float enable)
553{
554 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
555 return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
556}
557
558public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
559{
560 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
561 return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
562}
563
564public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
565{
566 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
567 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
568}
569
570public override bool CalculateTransforms(BulletConstraint constrain)
571{
572 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
573 return BSAPICPP.CalculateTransforms2(constrainu.ptr);
574}
575
576public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
577{
578 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
579 return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
580}
581
582public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
583{
584 BulletWorldUnman worldu = world as BulletWorldUnman;
585 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
586 return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
587}
588
589// =====================================================================================
590// btCollisionWorld entries
591public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
592{
593 BulletWorldUnman worldu = world as BulletWorldUnman;
594 BulletBodyUnman bodyu = obj as BulletBodyUnman;
595 BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
596}
597
598public override void UpdateAabbs(BulletWorld world)
599{
600 BulletWorldUnman worldu = world as BulletWorldUnman;
601 BSAPICPP.UpdateAabbs2(worldu.ptr);
602}
603
604public override bool GetForceUpdateAllAabbs(BulletWorld world)
605{
606 BulletWorldUnman worldu = world as BulletWorldUnman;
607 return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
608}
609
610public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
611{
612 BulletWorldUnman worldu = world as BulletWorldUnman;
613 BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
614}
615
616// =====================================================================================
617// btDynamicsWorld entries
618public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
619{
620 BulletWorldUnman worldu = world as BulletWorldUnman;
621 BulletBodyUnman bodyu = obj as BulletBodyUnman;
622
623 // Bullet resets several variables when an object is added to the world.
624 // Gravity is reset to world default depending on the static/dynamic
625 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
626 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
627
628 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
629
630 if (ret)
631 {
632 BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
633 obj.ApplyCollisionMask(world.physicsScene);
634 }
635 return ret;
636}
637
638public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
639{
640 BulletWorldUnman worldu = world as BulletWorldUnman;
641 BulletBodyUnman bodyu = obj as BulletBodyUnman;
642 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
643}
644
645public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
646{
647 BulletWorldUnman worldu = world as BulletWorldUnman;
648 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
649 return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
650}
651
652public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
653{
654 BulletWorldUnman worldu = world as BulletWorldUnman;
655 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
656 return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
657}
658// =====================================================================================
659// btCollisionObject entries
660public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
661{
662 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
663 return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
664}
665
666public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
667{
668 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
669 return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
670}
671
672public override bool HasAnisotripicFriction(BulletConstraint constrain)
673{
674 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
675 return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
676}
677
678public override void SetContactProcessingThreshold(BulletBody obj, float val)
679{
680 BulletBodyUnman bodyu = obj as BulletBodyUnman;
681 BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
682}
683
684public override float GetContactProcessingThreshold(BulletBody obj)
685{
686 BulletBodyUnman bodyu = obj as BulletBodyUnman;
687 return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
688}
689
690public override bool IsStaticObject(BulletBody obj)
691{
692 BulletBodyUnman bodyu = obj as BulletBodyUnman;
693 return BSAPICPP.IsStaticObject2(bodyu.ptr);
694}
695
696public override bool IsKinematicObject(BulletBody obj)
697{
698 BulletBodyUnman bodyu = obj as BulletBodyUnman;
699 return BSAPICPP.IsKinematicObject2(bodyu.ptr);
700}
701
702public override bool IsStaticOrKinematicObject(BulletBody obj)
703{
704 BulletBodyUnman bodyu = obj as BulletBodyUnman;
705 return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
706}
707
708public override bool HasContactResponse(BulletBody obj)
709{
710 BulletBodyUnman bodyu = obj as BulletBodyUnman;
711 return BSAPICPP.HasContactResponse2(bodyu.ptr);
712}
713
714public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
715{
716 BulletWorldUnman worldu = world as BulletWorldUnman;
717 BulletBodyUnman bodyu = obj as BulletBodyUnman;
718 BulletShapeUnman shapeu = shape as BulletShapeUnman;
719 if (worldu != null && bodyu != null)
720 {
721 // Special case to allow the caller to zero out the reference to any physical shape
722 if (shapeu != null)
723 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
724 else
725 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
726 }
727}
728
729public override BulletShape GetCollisionShape(BulletBody obj)
730{
731 BulletBodyUnman bodyu = obj as BulletBodyUnman;
732 return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
733}
734
735public override int GetActivationState(BulletBody obj)
736{
737 BulletBodyUnman bodyu = obj as BulletBodyUnman;
738 return BSAPICPP.GetActivationState2(bodyu.ptr);
739}
740
741public override void SetActivationState(BulletBody obj, int state)
742{
743 BulletBodyUnman bodyu = obj as BulletBodyUnman;
744 BSAPICPP.SetActivationState2(bodyu.ptr, state);
745}
746
747public override void SetDeactivationTime(BulletBody obj, float dtime)
748{
749 BulletBodyUnman bodyu = obj as BulletBodyUnman;
750 BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
751}
752
753public override float GetDeactivationTime(BulletBody obj)
754{
755 BulletBodyUnman bodyu = obj as BulletBodyUnman;
756 return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
757}
758
759public override void ForceActivationState(BulletBody obj, ActivationState state)
760{
761 BulletBodyUnman bodyu = obj as BulletBodyUnman;
762 BSAPICPP.ForceActivationState2(bodyu.ptr, state);
763}
764
765public override void Activate(BulletBody obj, bool forceActivation)
766{
767 BulletBodyUnman bodyu = obj as BulletBodyUnman;
768 BSAPICPP.Activate2(bodyu.ptr, forceActivation);
769}
770
771public override bool IsActive(BulletBody obj)
772{
773 BulletBodyUnman bodyu = obj as BulletBodyUnman;
774 return BSAPICPP.IsActive2(bodyu.ptr);
775}
776
777public override void SetRestitution(BulletBody obj, float val)
778{
779 BulletBodyUnman bodyu = obj as BulletBodyUnman;
780 BSAPICPP.SetRestitution2(bodyu.ptr, val);
781}
782
783public override float GetRestitution(BulletBody obj)
784{
785 BulletBodyUnman bodyu = obj as BulletBodyUnman;
786 return BSAPICPP.GetRestitution2(bodyu.ptr);
787}
788
789public override void SetFriction(BulletBody obj, float val)
790{
791 BulletBodyUnman bodyu = obj as BulletBodyUnman;
792 BSAPICPP.SetFriction2(bodyu.ptr, val);
793}
794
795public override float GetFriction(BulletBody obj)
796{
797 BulletBodyUnman bodyu = obj as BulletBodyUnman;
798 return BSAPICPP.GetFriction2(bodyu.ptr);
799}
800
801public override Vector3 GetPosition(BulletBody obj)
802{
803 BulletBodyUnman bodyu = obj as BulletBodyUnman;
804 return BSAPICPP.GetPosition2(bodyu.ptr);
805}
806
807public override Quaternion GetOrientation(BulletBody obj)
808{
809 BulletBodyUnman bodyu = obj as BulletBodyUnman;
810 return BSAPICPP.GetOrientation2(bodyu.ptr);
811}
812
813public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
814{
815 BulletBodyUnman bodyu = obj as BulletBodyUnman;
816 BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
817}
818
819 /*
820public override IntPtr GetBroadphaseHandle(BulletBody obj)
821{
822 BulletBodyUnman bodyu = obj as BulletBodyUnman;
823 return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
824}
825
826public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
827{
828 BulletBodyUnman bodyu = obj as BulletBodyUnman;
829 BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
830}
831 */
832
833public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
834{
835 BulletBodyUnman bodyu = obj as BulletBodyUnman;
836 BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
837}
838
839public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
840{
841 BulletBodyUnman bodyu = obj as BulletBodyUnman;
842 BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
843}
844
845public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
846{
847 BulletBodyUnman bodyu = obj as BulletBodyUnman;
848 BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
849}
850
851public override float GetHitFraction(BulletBody obj)
852{
853 BulletBodyUnman bodyu = obj as BulletBodyUnman;
854 return BSAPICPP.GetHitFraction2(bodyu.ptr);
855}
856
857public override void SetHitFraction(BulletBody obj, float val)
858{
859 BulletBodyUnman bodyu = obj as BulletBodyUnman;
860 BSAPICPP.SetHitFraction2(bodyu.ptr, val);
861}
862
863public override CollisionFlags GetCollisionFlags(BulletBody obj)
864{
865 BulletBodyUnman bodyu = obj as BulletBodyUnman;
866 return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
867}
868
869public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
870{
871 BulletBodyUnman bodyu = obj as BulletBodyUnman;
872 return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
873}
874
875public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
876{
877 BulletBodyUnman bodyu = obj as BulletBodyUnman;
878 return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
879}
880
881public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
882{
883 BulletBodyUnman bodyu = obj as BulletBodyUnman;
884 return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
885}
886
887public override float GetCcdMotionThreshold(BulletBody obj)
888{
889 BulletBodyUnman bodyu = obj as BulletBodyUnman;
890 return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
891}
892
893
894public override void SetCcdMotionThreshold(BulletBody obj, float val)
895{
896 BulletBodyUnman bodyu = obj as BulletBodyUnman;
897 BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
898}
899
900public override float GetCcdSweptSphereRadius(BulletBody obj)
901{
902 BulletBodyUnman bodyu = obj as BulletBodyUnman;
903 return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
904}
905
906public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
907{
908 BulletBodyUnman bodyu = obj as BulletBodyUnman;
909 BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
910}
911
912public override IntPtr GetUserPointer(BulletBody obj)
913{
914 BulletBodyUnman bodyu = obj as BulletBodyUnman;
915 return BSAPICPP.GetUserPointer2(bodyu.ptr);
916}
917
918public override void SetUserPointer(BulletBody obj, IntPtr val)
919{
920 BulletBodyUnman bodyu = obj as BulletBodyUnman;
921 BSAPICPP.SetUserPointer2(bodyu.ptr, val);
922}
923
924// =====================================================================================
925// btRigidBody entries
926public override void ApplyGravity(BulletBody obj)
927{
928 BulletBodyUnman bodyu = obj as BulletBodyUnman;
929 BSAPICPP.ApplyGravity2(bodyu.ptr);
930}
931
932public override void SetGravity(BulletBody obj, Vector3 val)
933{
934 BulletBodyUnman bodyu = obj as BulletBodyUnman;
935 BSAPICPP.SetGravity2(bodyu.ptr, val);
936}
937
938public override Vector3 GetGravity(BulletBody obj)
939{
940 BulletBodyUnman bodyu = obj as BulletBodyUnman;
941 return BSAPICPP.GetGravity2(bodyu.ptr);
942}
943
944public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
945{
946 BulletBodyUnman bodyu = obj as BulletBodyUnman;
947 BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
948}
949
950public override void SetLinearDamping(BulletBody obj, float lin_damping)
951{
952 BulletBodyUnman bodyu = obj as BulletBodyUnman;
953 BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
954}
955
956public override void SetAngularDamping(BulletBody obj, float ang_damping)
957{
958 BulletBodyUnman bodyu = obj as BulletBodyUnman;
959 BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
960}
961
962public override float GetLinearDamping(BulletBody obj)
963{
964 BulletBodyUnman bodyu = obj as BulletBodyUnman;
965 return BSAPICPP.GetLinearDamping2(bodyu.ptr);
966}
967
968public override float GetAngularDamping(BulletBody obj)
969{
970 BulletBodyUnman bodyu = obj as BulletBodyUnman;
971 return BSAPICPP.GetAngularDamping2(bodyu.ptr);
972}
973
974public override float GetLinearSleepingThreshold(BulletBody obj)
975{
976 BulletBodyUnman bodyu = obj as BulletBodyUnman;
977 return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
978}
979
980public override void ApplyDamping(BulletBody obj, float timeStep)
981{
982 BulletBodyUnman bodyu = obj as BulletBodyUnman;
983 BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
984}
985
986public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
987{
988 BulletBodyUnman bodyu = obj as BulletBodyUnman;
989 BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
990}
991
992public override Vector3 GetLinearFactor(BulletBody obj)
993{
994 BulletBodyUnman bodyu = obj as BulletBodyUnman;
995 return BSAPICPP.GetLinearFactor2(bodyu.ptr);
996}
997
998public override void SetLinearFactor(BulletBody obj, Vector3 factor)
999{
1000 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1001 BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
1002}
1003
1004public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
1005{
1006 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1007 BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
1008}
1009
1010// Add a force to the object as if its mass is one.
1011// Deep down in Bullet: m_totalForce += force*m_linearFactor;
1012public override void ApplyCentralForce(BulletBody obj, Vector3 force)
1013{
1014 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1015 BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
1016}
1017
1018// Set the force being applied to the object as if its mass is one.
1019public override void SetObjectForce(BulletBody obj, Vector3 force)
1020{
1021 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1022 BSAPICPP.SetObjectForce2(bodyu.ptr, force);
1023}
1024
1025public override Vector3 GetTotalForce(BulletBody obj)
1026{
1027 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1028 return BSAPICPP.GetTotalForce2(bodyu.ptr);
1029}
1030
1031public override Vector3 GetTotalTorque(BulletBody obj)
1032{
1033 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1034 return BSAPICPP.GetTotalTorque2(bodyu.ptr);
1035}
1036
1037public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
1038{
1039 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1040 return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
1041}
1042
1043public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
1044{
1045 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1046 BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
1047}
1048
1049public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
1050{
1051 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1052 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
1053}
1054
1055// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
1056public override void ApplyTorque(BulletBody obj, Vector3 torque)
1057{
1058 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1059 BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
1060}
1061
1062// Apply force at the given point. Will add torque to the object.
1063// Deep down in Bullet: applyCentralForce(force);
1064// applyTorque(rel_pos.cross(force*m_linearFactor));
1065public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
1066{
1067 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1068 BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
1069}
1070
1071// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1072// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
1073public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
1074{
1075 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1076 BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
1077}
1078
1079// Apply impulse to the object's torque. Force is scaled by object's mass.
1080// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
1081public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
1082{
1083 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1084 BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
1085}
1086
1087// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1088// Deep down in Bullet: applyCentralImpulse(impulse);
1089// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
1090public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
1091{
1092 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1093 BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
1094}
1095
1096public override void ClearForces(BulletBody obj)
1097{
1098 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1099 BSAPICPP.ClearForces2(bodyu.ptr);
1100}
1101
1102public override void ClearAllForces(BulletBody obj)
1103{
1104 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1105 BSAPICPP.ClearAllForces2(bodyu.ptr);
1106}
1107
1108public override void UpdateInertiaTensor(BulletBody obj)
1109{
1110 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1111 BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
1112}
1113
1114public override Vector3 GetLinearVelocity(BulletBody obj)
1115{
1116 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1117 return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
1118}
1119
1120public override Vector3 GetAngularVelocity(BulletBody obj)
1121{
1122 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1123 return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
1124}
1125
1126public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
1127{
1128 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1129 BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
1130}
1131
1132public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
1133{
1134 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1135 BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
1136}
1137
1138public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
1139{
1140 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1141 return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
1142}
1143
1144public override void Translate(BulletBody obj, Vector3 trans)
1145{
1146 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1147 BSAPICPP.Translate2(bodyu.ptr, trans);
1148}
1149
1150public override void UpdateDeactivation(BulletBody obj, float timeStep)
1151{
1152 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1153 BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
1154}
1155
1156public override bool WantsSleeping(BulletBody obj)
1157{
1158 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1159 return BSAPICPP.WantsSleeping2(bodyu.ptr);
1160}
1161
1162public override void SetAngularFactor(BulletBody obj, float factor)
1163{
1164 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1165 BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
1166}
1167
1168public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
1169{
1170 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1171 BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
1172}
1173
1174public override Vector3 GetAngularFactor(BulletBody obj)
1175{
1176 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1177 return BSAPICPP.GetAngularFactor2(bodyu.ptr);
1178}
1179
1180public override bool IsInWorld(BulletWorld world, BulletBody obj)
1181{
1182 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1183 return BSAPICPP.IsInWorld2(bodyu.ptr);
1184}
1185
1186public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
1187{
1188 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1189 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1190 BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
1191}
1192
1193public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
1194{
1195 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1196 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1197 BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
1198}
1199
1200public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
1201{
1202 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1203 return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
1204}
1205
1206public override int GetNumConstraintRefs(BulletBody obj)
1207{
1208 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1209 return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
1210}
1211
1212public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
1213{
1214 BulletBodyUnman bodyu = body as BulletBodyUnman;
1215 return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
1216}
1217
1218// =====================================================================================
1219// btCollisionShape entries
1220
1221public override float GetAngularMotionDisc(BulletShape shape)
1222{
1223 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1224 return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
1225}
1226
1227public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
1228{
1229 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1230 return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
1231}
1232
1233public override bool IsPolyhedral(BulletShape shape)
1234{
1235 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1236 return BSAPICPP.IsPolyhedral2(shapeu.ptr);
1237}
1238
1239public override bool IsConvex2d(BulletShape shape)
1240{
1241 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1242 return BSAPICPP.IsConvex2d2(shapeu.ptr);
1243}
1244
1245public override bool IsConvex(BulletShape shape)
1246{
1247 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1248 return BSAPICPP.IsConvex2(shapeu.ptr);
1249}
1250
1251public override bool IsNonMoving(BulletShape shape)
1252{
1253 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1254 return BSAPICPP.IsNonMoving2(shapeu.ptr);
1255}
1256
1257public override bool IsConcave(BulletShape shape)
1258{
1259 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1260 return BSAPICPP.IsConcave2(shapeu.ptr);
1261}
1262
1263public override bool IsCompound(BulletShape shape)
1264{
1265 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1266 return BSAPICPP.IsCompound2(shapeu.ptr);
1267}
1268
1269public override bool IsSoftBody(BulletShape shape)
1270{
1271 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1272 return BSAPICPP.IsSoftBody2(shapeu.ptr);
1273}
1274
1275public override bool IsInfinite(BulletShape shape)
1276{
1277 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1278 return BSAPICPP.IsInfinite2(shapeu.ptr);
1279}
1280
1281public override void SetLocalScaling(BulletShape shape, Vector3 scale)
1282{
1283 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1284 BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
1285}
1286
1287public override Vector3 GetLocalScaling(BulletShape shape)
1288{
1289 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1290 return BSAPICPP.GetLocalScaling2(shapeu.ptr);
1291}
1292
1293public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
1294{
1295 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1296 return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
1297}
1298
1299public override int GetShapeType(BulletShape shape)
1300{
1301 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1302 return BSAPICPP.GetShapeType2(shapeu.ptr);
1303}
1304
1305public override void SetMargin(BulletShape shape, float val)
1306{
1307 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1308 BSAPICPP.SetMargin2(shapeu.ptr, val);
1309}
1310
1311public override float GetMargin(BulletShape shape)
1312{
1313 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1314 return BSAPICPP.GetMargin2(shapeu.ptr);
1315}
1316
1317// =====================================================================================
1318// Debugging
1319public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1320{
1321 BulletWorldUnman worldu = world as BulletWorldUnman;
1322 BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
1323 BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
1324}
1325
1326public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
1327{
1328 BulletWorldUnman worldu = world as BulletWorldUnman;
1329 BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
1330 BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
1331}
1332
1333public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
1334{
1335 BulletWorldUnman worldu = world as BulletWorldUnman;
1336 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1337 BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
1338}
1339
1340public override void DumpActivationInfo(BulletWorld world)
1341{
1342 BulletWorldUnman worldu = world as BulletWorldUnman;
1343 BSAPICPP.DumpActivationInfo2(worldu.ptr);
1344}
1345
1346public override void DumpAllInfo(BulletWorld world)
1347{
1348 BulletWorldUnman worldu = world as BulletWorldUnman;
1349 BSAPICPP.DumpAllInfo2(worldu.ptr);
1350}
1351
1352public override void DumpPhysicsStatistics(BulletWorld world)
1353{
1354 BulletWorldUnman worldu = world as BulletWorldUnman;
1355 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1356}
1357public override void ResetBroadphasePool(BulletWorld world)
1358{
1359 BulletWorldUnman worldu = world as BulletWorldUnman;
1360 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1361}
1362public override void ResetConstraintSolver(BulletWorld world)
1363{
1364 BulletWorldUnman worldu = world as BulletWorldUnman;
1365 BSAPICPP.ResetConstraintSolver(worldu.ptr);
1366}
1367
1368// =====================================================================================
1369// =====================================================================================
1370// =====================================================================================
1371// =====================================================================================
1372// =====================================================================================
1373// The actual interface to the unmanaged code
1374static class BSAPICPP
1375{
1376// ===============================================================================
1377// Link back to the managed code for outputting log messages
1378[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1379public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
1380
1381// ===============================================================================
1382// Initialization and simulation
1383[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1384public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
1385 int maxCollisions, IntPtr collisionArray,
1386 int maxUpdates, IntPtr updateArray,
1387 DebugLogCallback logRoutine);
1388
1389[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1390public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
1391 out int updatedEntityCount, out int collidersCount);
1392
1393[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1394public static extern void Shutdown2(IntPtr sim);
1395
1396[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1397public static extern bool PushUpdate2(IntPtr obj);
1398
1399[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1400public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
1401
1402// =====================================================================================
1403// Mesh, hull, shape and body creation helper routines
1404[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1405public static extern IntPtr CreateMeshShape2(IntPtr world,
1406 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1407 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1408
1409[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1410public static extern IntPtr CreateHullShape2(IntPtr world,
1411 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1412
1413[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1414public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1415
1416[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1417public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1418
1419[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1420public static extern bool IsNativeShape2(IntPtr shape);
1421
1422[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1423public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
1424
1425[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1426public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
1427
1428[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1429public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
1430
1431[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1432public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
1433
1434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1435public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
1436
1437[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1438public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1439
1440[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1441public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1442
1443[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1444public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1445
1446[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1447public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
1448
1449[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1450public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1451
1452[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1453public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
1454
1455[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1456public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
1457
1458[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1459public static extern int GetBodyType2(IntPtr obj);
1460
1461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1462public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1463
1464[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1465public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1466
1467[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1468public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1469
1470[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1471public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1472
1473// =====================================================================================
1474// Terrain creation and helper routines
1475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1476public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1477
1478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1479public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1480 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1481 float scaleFactor, float collisionMargin);
1482
1483// =====================================================================================
1484// Constraint creation and helper routines
1485[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1486public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1487 Vector3 frame1loc, Quaternion frame1rot,
1488 Vector3 frame2loc, Quaternion frame2rot,
1489 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1490
1491[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1492public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1493 Vector3 joinPoint,
1494 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1495
1496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1497public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1,
1498 Vector3 frameInBloc, Quaternion frameInBrot,
1499 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
1500
1501[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1502public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1503 Vector3 frame1loc, Quaternion frame1rot,
1504 Vector3 frame2loc, Quaternion frame2rot,
1505 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1506
1507[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1508public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1509 Vector3 pivotinA, Vector3 pivotinB,
1510 Vector3 axisInA, Vector3 axisInB,
1511 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1512
1513[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1514public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1515 Vector3 frameInAloc, Quaternion frameInArot,
1516 Vector3 frameInBloc, Quaternion frameInBrot,
1517 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1518
1519[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1520public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1521 Vector3 frameInAloc, Quaternion frameInArot,
1522 Vector3 frameInBloc, Quaternion frameInBrot,
1523 bool disableCollisionsBetweenLinkedBodies);
1524
1525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1526public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1527 Vector3 axisInA, Vector3 axisInB,
1528 float ratio, bool disableCollisionsBetweenLinkedBodies);
1529
1530[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1531public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1532 Vector3 pivotInA, Vector3 pivotInB,
1533 bool disableCollisionsBetweenLinkedBodies);
1534
1535
1536[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1537public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1538
1539[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1540public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
1541
1542[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1543public static extern bool SetFrames2(IntPtr constrain,
1544 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
1545
1546[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1547public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1548
1549[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1550public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1551
1552[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1553public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
1554
1555[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1556public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
1557
1558[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1559public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1560
1561[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1562public static extern bool CalculateTransforms2(IntPtr constrain);
1563
1564[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1565public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
1566
1567[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1568public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
1569
1570// =====================================================================================
1571// btCollisionWorld entries
1572[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1573public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
1574
1575[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1576public static extern void UpdateAabbs2(IntPtr world);
1577
1578[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1579public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
1580
1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1582public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
1583
1584// =====================================================================================
1585// btDynamicsWorld entries
1586[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1587public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1588
1589[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1590public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1591
1592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1593public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1594
1595[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1596public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
1597// =====================================================================================
1598// btCollisionObject entries
1599[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1600public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
1601
1602[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1603public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
1604
1605[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1606public static extern bool HasAnisotripicFriction2(IntPtr constrain);
1607
1608[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1609public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
1610
1611[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1612public static extern float GetContactProcessingThreshold2(IntPtr obj);
1613
1614[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1615public static extern bool IsStaticObject2(IntPtr obj);
1616
1617[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1618public static extern bool IsKinematicObject2(IntPtr obj);
1619
1620[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1621public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
1622
1623[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1624public static extern bool HasContactResponse2(IntPtr obj);
1625
1626[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1627public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
1628
1629[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1630public static extern IntPtr GetCollisionShape2(IntPtr obj);
1631
1632[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1633public static extern int GetActivationState2(IntPtr obj);
1634
1635[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1636public static extern void SetActivationState2(IntPtr obj, int state);
1637
1638[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1639public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
1640
1641[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1642public static extern float GetDeactivationTime2(IntPtr obj);
1643
1644[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1645public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
1646
1647[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1648public static extern void Activate2(IntPtr obj, bool forceActivation);
1649
1650[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1651public static extern bool IsActive2(IntPtr obj);
1652
1653[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1654public static extern void SetRestitution2(IntPtr obj, float val);
1655
1656[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1657public static extern float GetRestitution2(IntPtr obj);
1658
1659[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1660public static extern void SetFriction2(IntPtr obj, float val);
1661
1662[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1663public static extern float GetFriction2(IntPtr obj);
1664
1665 /* Haven't defined the type 'Transform'
1666[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1667public static extern Transform GetWorldTransform2(IntPtr obj);
1668
1669[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1670public static extern void setWorldTransform2(IntPtr obj, Transform trans);
1671 */
1672
1673[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1674public static extern Vector3 GetPosition2(IntPtr obj);
1675
1676[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1677public static extern Quaternion GetOrientation2(IntPtr obj);
1678
1679[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1680public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
1681
1682[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1683public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
1684
1685[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1686public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
1687
1688 /*
1689[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1690public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
1691
1692[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1693public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
1694 */
1695
1696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1697public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
1698
1699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1700public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
1701
1702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1703public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
1704
1705[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1706public static extern float GetHitFraction2(IntPtr obj);
1707
1708[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1709public static extern void SetHitFraction2(IntPtr obj, float val);
1710
1711[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1712public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1713
1714[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1715public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1716
1717[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1718public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1719
1720[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1721public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1722
1723[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1724public static extern float GetCcdMotionThreshold2(IntPtr obj);
1725
1726[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1727public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
1728
1729[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1730public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
1731
1732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1733public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
1734
1735[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1736public static extern IntPtr GetUserPointer2(IntPtr obj);
1737
1738[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1739public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
1740
1741// =====================================================================================
1742// btRigidBody entries
1743[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1744public static extern void ApplyGravity2(IntPtr obj);
1745
1746[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1747public static extern void SetGravity2(IntPtr obj, Vector3 val);
1748
1749[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1750public static extern Vector3 GetGravity2(IntPtr obj);
1751
1752[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1753public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
1754
1755[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1756public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
1757
1758[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1759public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
1760
1761[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1762public static extern float GetLinearDamping2(IntPtr obj);
1763
1764[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1765public static extern float GetAngularDamping2(IntPtr obj);
1766
1767[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1768public static extern float GetLinearSleepingThreshold2(IntPtr obj);
1769
1770[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1771public static extern float GetAngularSleepingThreshold2(IntPtr obj);
1772
1773[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1774public static extern void ApplyDamping2(IntPtr obj, float timeStep);
1775
1776[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1777public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
1778
1779[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1780public static extern Vector3 GetLinearFactor2(IntPtr obj);
1781
1782[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1783public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
1784
1785 /*
1786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1787public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
1788 */
1789
1790[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1791public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
1792
1793// Add a force to the object as if its mass is one.
1794[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1795public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
1796
1797// Set the force being applied to the object as if its mass is one.
1798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1799public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
1800
1801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1802public static extern Vector3 GetTotalForce2(IntPtr obj);
1803
1804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1805public static extern Vector3 GetTotalTorque2(IntPtr obj);
1806
1807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1808public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
1809
1810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1811public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
1812
1813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1814public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
1815
1816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1817public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
1818
1819// Apply force at the given point. Will add torque to the object.
1820[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1821public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
1822
1823// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1824[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1825public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
1826
1827// Apply impulse to the object's torque. Force is scaled by object's mass.
1828[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1829public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
1830
1831// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1833public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
1834
1835[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1836public static extern void ClearForces2(IntPtr obj);
1837
1838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1839public static extern void ClearAllForces2(IntPtr obj);
1840
1841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1842public static extern void UpdateInertiaTensor2(IntPtr obj);
1843
1844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1845public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
1846
1847 /*
1848[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1849public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
1850 */
1851
1852[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1853public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1854
1855[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1856public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1857
1858[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1859public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1860
1861[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1862public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1863
1864[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1865public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1866
1867[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1868public static extern void Translate2(IntPtr obj, Vector3 trans);
1869
1870[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1871public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1872
1873[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1874public static extern bool WantsSleeping2(IntPtr obj);
1875
1876[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1877public static extern void SetAngularFactor2(IntPtr obj, float factor);
1878
1879[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1880public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1881
1882[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1883public static extern Vector3 GetAngularFactor2(IntPtr obj);
1884
1885[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1886public static extern bool IsInWorld2(IntPtr obj);
1887
1888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1889public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1890
1891[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1892public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1893
1894[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1895public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1896
1897[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1898public static extern int GetNumConstraintRefs2(IntPtr obj);
1899
1900[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1901public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
1902
1903// =====================================================================================
1904// btCollisionShape entries
1905
1906[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1907public static extern float GetAngularMotionDisc2(IntPtr shape);
1908
1909[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1910public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1911
1912[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1913public static extern bool IsPolyhedral2(IntPtr shape);
1914
1915[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1916public static extern bool IsConvex2d2(IntPtr shape);
1917
1918[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1919public static extern bool IsConvex2(IntPtr shape);
1920
1921[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1922public static extern bool IsNonMoving2(IntPtr shape);
1923
1924[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1925public static extern bool IsConcave2(IntPtr shape);
1926
1927[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1928public static extern bool IsCompound2(IntPtr shape);
1929
1930[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1931public static extern bool IsSoftBody2(IntPtr shape);
1932
1933[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1934public static extern bool IsInfinite2(IntPtr shape);
1935
1936[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1937public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
1938
1939[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1940public static extern Vector3 GetLocalScaling2(IntPtr shape);
1941
1942[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1943public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
1944
1945[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1946public static extern int GetShapeType2(IntPtr shape);
1947
1948[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1949public static extern void SetMargin2(IntPtr shape, float val);
1950
1951[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1952public static extern float GetMargin2(IntPtr shape);
1953
1954// =====================================================================================
1955// Debugging
1956[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1957public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1958
1959[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1960public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1961
1962[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1963public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1964
1965[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1966public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1967
1968[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1969public static extern void DumpActivationInfo2(IntPtr sim);
1970
1971[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1972public static extern void DumpAllInfo2(IntPtr sim);
1973
1974[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1975public static extern void DumpPhysicsStatistics2(IntPtr sim);
1976
1977[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1978public static extern void ResetBroadphasePool(IntPtr sim);
1979
1980[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1981public static extern void ResetConstraintSolver(IntPtr sim);
1982
1983}
1984
1985}
1986
1987}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
new file mode 100755
index 0000000..6fc10e9
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -0,0 +1,2311 @@
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.Runtime.InteropServices;
31using System.Text;
32
33using OpenSim.Framework;
34
35using OpenMetaverse;
36
37using BulletXNA;
38using BulletXNA.LinearMath;
39using BulletXNA.BulletCollision;
40using BulletXNA.BulletDynamics;
41using BulletXNA.BulletCollision.CollisionDispatch;
42
43namespace OpenSim.Region.Physics.BulletSPlugin
44{
45public sealed class BSAPIXNA : BSAPITemplate
46{
47private sealed class BulletWorldXNA : BulletWorld
48{
49 public DiscreteDynamicsWorld world;
50 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
51 : base(id, physScene)
52 {
53 world = xx;
54 }
55}
56
57private sealed class BulletBodyXNA : BulletBody
58{
59 public CollisionObject body;
60 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
61
62 public BulletBodyXNA(uint id, CollisionObject xx)
63 : base(id)
64 {
65 body = xx;
66 }
67 public override bool HasPhysicalBody
68 {
69 get { return body != null; }
70 }
71 public override void Clear()
72 {
73 body = null;
74 }
75 public override string AddrString
76 {
77 get { return "XNARigidBody"; }
78 }
79}
80
81private sealed class BulletShapeXNA : BulletShape
82{
83 public CollisionShape shape;
84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
85 : base()
86 {
87 shape = xx;
88 type = typ;
89 }
90 public override bool HasPhysicalShape
91 {
92 get { return shape != null; }
93 }
94 public override void Clear()
95 {
96 shape = null;
97 }
98 public override BulletShape Clone()
99 {
100 return new BulletShapeXNA(shape, type);
101 }
102 public override bool ReferenceSame(BulletShape other)
103 {
104 BulletShapeXNA otheru = other as BulletShapeXNA;
105 return (otheru != null) && (this.shape == otheru.shape);
106
107 }
108 public override string AddrString
109 {
110 get { return "XNACollisionShape"; }
111 }
112}
113private sealed class BulletConstraintXNA : BulletConstraint
114{
115 public TypedConstraint constrain;
116 public BulletConstraintXNA(TypedConstraint xx) : base()
117 {
118 constrain = xx;
119 }
120
121 public override void Clear()
122 {
123 constrain = null;
124 }
125 public override bool HasPhysicalConstraint { get { return constrain != null; } }
126
127 // Used for log messages for a unique display of the memory/object allocated to this instance
128 public override string AddrString
129 {
130 get { return "XNAConstraint"; }
131 }
132}
133 internal int m_maxCollisions;
134 internal CollisionDesc[] UpdatedCollisions;
135 internal int LastCollisionDesc = 0;
136 internal int m_maxUpdatesPerFrame;
137 internal int LastEntityProperty = 0;
138
139 internal EntityProperties[] UpdatedObjects;
140 internal Dictionary<uint, GhostObject> specialCollisionObjects;
141
142 private static int m_collisionsThisFrame;
143 private BSScene PhysicsScene { get; set; }
144
145 public override string BulletEngineName { get { return "BulletXNA"; } }
146 public override string BulletEngineVersion { get; protected set; }
147
148 public BSAPIXNA(string paramName, BSScene physScene)
149 {
150 PhysicsScene = physScene;
151 }
152
153 /// <summary>
154 ///
155 /// </summary>
156 /// <param name="p"></param>
157 /// <param name="p_2"></param>
158 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
159 {
160 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
161 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
162 CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
163 if (body != null)
164 world.RemoveRigidBody(body);
165 else if (collisionObject != null)
166 world.RemoveCollisionObject(collisionObject);
167 else
168 return false;
169 return true;
170 }
171
172 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
173 {
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
176 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
177
178 return true;
179
180 }
181
182 public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint)
183 {
184 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
185 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
186 world.RemoveConstraint(constraint);
187 return true;
188 }
189
190 public override void SetRestitution(BulletBody pCollisionObject, float pRestitution)
191 {
192 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
193 collisionObject.SetRestitution(pRestitution);
194 }
195
196 public override int GetShapeType(BulletShape pShape)
197 {
198 CollisionShape shape = (pShape as BulletShapeXNA).shape;
199 return (int)shape.GetShapeType();
200 }
201 public override void SetMargin(BulletShape pShape, float pMargin)
202 {
203 CollisionShape shape = (pShape as BulletShapeXNA).shape;
204 shape.SetMargin(pMargin);
205 }
206
207 public override float GetMargin(BulletShape pShape)
208 {
209 CollisionShape shape = (pShape as BulletShapeXNA).shape;
210 return shape.GetMargin();
211 }
212
213 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
214 {
215 CollisionShape shape = (pShape as BulletShapeXNA).shape;
216 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
217 shape.SetLocalScaling(ref vec);
218
219 }
220
221 public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold)
222 {
223 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
224 collisionObject.SetContactProcessingThreshold(contactprocessingthreshold);
225 }
226
227 public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold)
228 {
229 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
230 collisionObject.SetCcdMotionThreshold(pccdMotionThreashold);
231 }
232
233 public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius)
234 {
235 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
236 collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
237 }
238
239 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
240 {
241 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
242 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
243 }
244
245 public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
246 {
247 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
248 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
249 existingcollisionFlags |= pcollisionFlags;
250 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
251 return (CollisionFlags) (uint) existingcollisionFlags;
252 }
253
254 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
255 {
256 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
257 CollisionObject cbody = (pBody as BulletBodyXNA).body;
258 RigidBody rbody = cbody as RigidBody;
259
260 // Bullet resets several variables when an object is added to the world. In particular,
261 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
262 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
263 IndexedMatrix origPos = cbody.GetWorldTransform();
264 if (rbody != null)
265 {
266 IndexedVector3 origGrav = rbody.GetGravity();
267 world.AddRigidBody(rbody);
268 rbody.SetGravity(origGrav);
269 }
270 else
271 {
272 world.AddCollisionObject(cbody);
273 }
274 cbody.SetWorldTransform(origPos);
275
276 pBody.ApplyCollisionMask(pWorld.physicsScene);
277
278 //if (body.GetBroadphaseHandle() != null)
279 // world.UpdateSingleAabb(body);
280 return true;
281 }
282
283 public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState)
284 {
285 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
286 collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
287 }
288
289 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject)
290 {
291 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
292 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
293 world.UpdateSingleAabb(collisionObject);
294 }
295
296 public override void UpdateAabbs(BulletWorld pWorld) {
297 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
298 world.UpdateAabbs();
299 }
300 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
301 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
302 return world.GetForceUpdateAllAabbs();
303
304 }
305 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
306 {
307 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
308 world.SetForceUpdateAllAabbs(pForce);
309 }
310
311 public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask)
312 {
313 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
314 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
315 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
316 if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0)
317 return false;
318 return true;
319 }
320
321 public override void ClearAllForces(BulletBody pCollisionObject)
322 {
323 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
324 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
325 collisionObject.SetInterpolationLinearVelocity(ref zeroVector);
326 collisionObject.SetInterpolationAngularVelocity(ref zeroVector);
327 IndexedMatrix bodytransform = collisionObject.GetWorldTransform();
328
329 collisionObject.SetInterpolationWorldTransform(ref bodytransform);
330
331 if (collisionObject is RigidBody)
332 {
333 RigidBody rigidbody = collisionObject as RigidBody;
334 rigidbody.SetLinearVelocity(zeroVector);
335 rigidbody.SetAngularVelocity(zeroVector);
336 rigidbody.ClearForces();
337 }
338 }
339
340 public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3)
341 {
342 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
343 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
344 collisionObject.SetInterpolationAngularVelocity(ref vec);
345 }
346
347 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
348 {
349 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
350 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
351 body.SetAngularVelocity(ref vec);
352 }
353 public override Vector3 GetTotalForce(BulletBody pBody)
354 {
355 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
356 IndexedVector3 iv3 = body.GetTotalForce();
357 return new Vector3(iv3.X, iv3.Y, iv3.Z);
358 }
359 public override Vector3 GetTotalTorque(BulletBody pBody)
360 {
361 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
362 IndexedVector3 iv3 = body.GetTotalTorque();
363 return new Vector3(iv3.X, iv3.Y, iv3.Z);
364 }
365 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
366 {
367 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
368 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
369 return new Vector3(iv3.X, iv3.Y, iv3.Z);
370 }
371 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
372 {
373 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
374 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
375 body.SetInvInertiaDiagLocal(ref iv3);
376 }
377 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
378 {
379 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
380 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
381 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
382 body.ApplyForce(ref forceiv3, ref posiv3);
383 }
384 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
385 {
386 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
387 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
388 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
389 body.ApplyImpulse(ref impiv3, ref posiv3);
390 }
391
392 public override void ClearForces(BulletBody pBody)
393 {
394 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
395 body.ClearForces();
396 }
397
398 public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation)
399 {
400 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
401 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
402 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
403 _orientation.W);
404 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
405 mat._origin = vposition;
406 collisionObject.SetWorldTransform(mat);
407
408 }
409
410 public override Vector3 GetPosition(BulletBody pCollisionObject)
411 {
412 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
413 IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin;
414 return new Vector3(pos.X, pos.Y, pos.Z);
415 }
416
417 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
418 {
419 CollisionShape shape = (pShape as BulletShapeXNA).shape;
420 IndexedVector3 inertia = IndexedVector3.Zero;
421 shape.CalculateLocalInertia(pphysMass, out inertia);
422 return new Vector3(inertia.X, inertia.Y, inertia.Z);
423 }
424
425 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
426 {
427 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
428 if (body != null) // Can't set mass props on collision object.
429 {
430 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
431 body.SetMassProps(pphysMass, inertia);
432 }
433 }
434
435
436 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
437 {
438 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
439 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
440 body.SetTotalForce(ref force);
441 }
442
443 public override void SetFriction(BulletBody pCollisionObject, float _currentFriction)
444 {
445 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
446 collisionObject.SetFriction(_currentFriction);
447 }
448
449 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
450 {
451 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
452 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
453 body.SetLinearVelocity(velocity);
454 }
455
456 public override void Activate(BulletBody pCollisionObject, bool pforceactivation)
457 {
458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
459 collisionObject.Activate(pforceactivation);
460
461 }
462
463 public override Quaternion GetOrientation(BulletBody pCollisionObject)
464 {
465 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
466 IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation();
467 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
468 }
469
470 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
471 {
472 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
473 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
474 existingcollisionFlags &= ~pcollisionFlags;
475 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
476 return (CollisionFlags)(uint)existingcollisionFlags;
477 }
478
479 public override float GetCcdMotionThreshold(BulletBody pCollisionObject)
480 {
481 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
482 return collisionObject.GetCcdSquareMotionThreshold();
483 }
484
485 public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject)
486 {
487 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
488 return collisionObject.GetCcdSweptSphereRadius();
489
490 }
491
492 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
493 {
494 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
495 return (IntPtr)shape.GetUserPointer();
496 }
497
498 public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val)
499 {
500 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
501 shape.SetUserPointer(val);
502 }
503
504 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
505 {
506 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
507 if (body != null) // Can't set collisionobject.set gravity
508 {
509 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
510 body.SetGravity(gravity);
511 }
512 }
513
514 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
515 {
516 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
517 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
518 world.RemoveConstraint(constraint);
519 return true;
520 }
521
522 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
523 {
524 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
525 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
526 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
527 constraint.SetLinearLowerLimit(lowlimit);
528 constraint.SetLinearUpperLimit(highlimit);
529 return true;
530 }
531
532 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
533 {
534 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
535 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
536 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
537 constraint.SetAngularLowerLimit(lowlimit);
538 constraint.SetAngularUpperLimit(highlimit);
539 return true;
540 }
541
542 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
543 {
544 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
545 constraint.SetOverrideNumSolverIterations((int)cnt);
546 }
547
548 public override bool CalculateTransforms(BulletConstraint pConstraint)
549 {
550 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
551 constraint.CalculateTransforms();
552 return true;
553 }
554
555 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
556 {
557 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
558 constraint.SetEnabled((p_2 == 0) ? false : true);
559 }
560
561
562 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
563 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
564 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
565
566 {
567 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
568 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
569 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
570 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
571 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
572 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
573 frame1._origin = frame1v;
574
575 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
576 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
577 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
578 frame2._origin = frame1v;
579
580 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
581 puseLinearReferenceFrameA);
582 consttr.CalculateTransforms();
583 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
584
585 return new BulletConstraintXNA(consttr);
586 }
587
588 public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1,
589 Vector3 pframe1, Quaternion pframe1rot,
590 bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies)
591 {
592 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
593 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
594 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
595 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
596 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
597 frame1._origin = frame1v;
598
599 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB);
600 consttr.CalculateTransforms();
601 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
602
603 return new BulletConstraintXNA(consttr);
604 }
605
606 /// <summary>
607 ///
608 /// </summary>
609 /// <param name="pWorld"></param>
610 /// <param name="pBody1"></param>
611 /// <param name="pBody2"></param>
612 /// <param name="pjoinPoint"></param>
613 /// <param name="puseLinearReferenceFrameA"></param>
614 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
615 /// <returns></returns>
616 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
617 {
618 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
619 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
620 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
621 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
622 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
623
624 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
625 IndexedMatrix mat = IndexedMatrix.Identity;
626 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
627 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
628 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
629
630 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
631 consttr.CalculateTransforms();
632 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
633
634 return new BulletConstraintXNA(consttr);
635 }
636 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
637 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
638 {
639 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
640 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
641 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
642 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
643 frame1._origin = frame1v;
644
645 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
646 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
647 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
648 frame2._origin = frame1v;
649 constraint.SetFrames(ref frame1, ref frame2);
650 return true;
651 }
652
653 public override Vector3 GetLinearVelocity(BulletBody pBody)
654 {
655 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
656 IndexedVector3 iv3 = body.GetLinearVelocity();
657 return new Vector3(iv3.X, iv3.Y, iv3.Z);
658 }
659 public override Vector3 GetAngularVelocity(BulletBody pBody)
660 {
661 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
662 IndexedVector3 iv3 = body.GetAngularVelocity();
663 return new Vector3(iv3.X, iv3.Y, iv3.Z);
664 }
665 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
666 {
667 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
668 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
669 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
670 return new Vector3(iv3.X, iv3.Y, iv3.Z);
671 }
672 public override void Translate(BulletBody pCollisionObject, Vector3 trans)
673 {
674 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
675 collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z));
676 }
677 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
678 {
679 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
680 body.UpdateDeactivation(timeStep);
681 }
682
683 public override bool WantsSleeping(BulletBody pBody)
684 {
685 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
686 return body.WantsSleeping();
687 }
688
689 public override void SetAngularFactor(BulletBody pBody, float factor)
690 {
691 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
692 body.SetAngularFactor(factor);
693 }
694
695 public override Vector3 GetAngularFactor(BulletBody pBody)
696 {
697 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
698 IndexedVector3 iv3 = body.GetAngularFactor();
699 return new Vector3(iv3.X, iv3.Y, iv3.Z);
700 }
701
702 public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject)
703 {
704 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
705 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
706 return world.IsInWorld(collisionObject);
707 }
708
709 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
710 {
711 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
712 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
713 body.AddConstraintRef(constrain);
714 }
715
716 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
717 {
718 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
719 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
720 body.RemoveConstraintRef(constrain);
721 }
722
723 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
724 {
725 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
726 return new BulletConstraintXNA(body.GetConstraintRef(index));
727 }
728
729 public override int GetNumConstraintRefs(BulletBody pBody)
730 {
731 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
732 return body.GetNumConstraintRefs();
733 }
734
735 public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity)
736 {
737 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
738 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
739 collisionObject.SetInterpolationLinearVelocity(ref velocity);
740 }
741
742 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
743 {
744 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
745 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
746 return true;
747 }
748 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
749 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
750 {
751 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
752 constraint.SetBreakingImpulseThreshold(threshold);
753 return true;
754 }
755 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
756 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
757 {
758 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
759 float lineardamping = body.GetLinearDamping();
760 body.SetDamping(lineardamping, angularDamping);
761
762 }
763
764 public override void UpdateInertiaTensor(BulletBody pBody)
765 {
766 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
767 if (body != null) // can't update inertia tensor on CollisionObject
768 body.UpdateInertiaTensor();
769 }
770
771 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
772 {
773 CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
774 shape.RecalculateLocalAabb();
775 }
776
777 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
778 public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject)
779 {
780 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
781 uint flags = (uint)collisionObject.GetCollisionFlags();
782 return (CollisionFlags) flags;
783 }
784
785 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
786 {
787 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
788 body.SetDamping(pLinear, pAngular);
789 }
790 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
791 public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime)
792 {
793 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
794 collisionObject.SetDeactivationTime(pDeactivationTime);
795 }
796 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
797 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
798 {
799 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
800 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
801 }
802
803 public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject)
804 {
805 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
806 return (CollisionObjectTypes)(int) collisionObject.GetInternalType();
807 }
808
809 public override void ApplyGravity(BulletBody pBody)
810 {
811
812 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
813 body.ApplyGravity();
814 }
815
816 public override Vector3 GetGravity(BulletBody pBody)
817 {
818 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
819 IndexedVector3 gravity = body.GetGravity();
820 return new Vector3(gravity.X, gravity.Y, gravity.Z);
821 }
822
823 public override void SetLinearDamping(BulletBody pBody, float lin_damping)
824 {
825 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
826 float angularDamping = body.GetAngularDamping();
827 body.SetDamping(lin_damping, angularDamping);
828 }
829
830 public override float GetLinearDamping(BulletBody pBody)
831 {
832 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
833 return body.GetLinearDamping();
834 }
835
836 public override float GetAngularDamping(BulletBody pBody)
837 {
838 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
839 return body.GetAngularDamping();
840 }
841
842 public override float GetLinearSleepingThreshold(BulletBody pBody)
843 {
844 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
845 return body.GetLinearSleepingThreshold();
846 }
847
848 public override void ApplyDamping(BulletBody pBody, float timeStep)
849 {
850 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
851 body.ApplyDamping(timeStep);
852 }
853
854 public override Vector3 GetLinearFactor(BulletBody pBody)
855 {
856 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
857 IndexedVector3 linearFactor = body.GetLinearFactor();
858 return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z);
859 }
860
861 public override void SetLinearFactor(BulletBody pBody, Vector3 factor)
862 {
863 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
864 body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z));
865 }
866
867 public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot)
868 {
869 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
870 IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W);
871 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat);
872 mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z);
873 body.SetCenterOfMassTransform( ref mat);
874 /* TODO: double check this */
875 }
876
877 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
878 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
879 {
880 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
881 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
882 body.ApplyCentralForce(ref fSum);
883 }
884 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
885 {
886 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
887 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
888 body.ApplyCentralImpulse(ref fSum);
889 }
890 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
891 {
892 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
893 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
894 body.ApplyTorque(ref fSum);
895 }
896 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
897 {
898 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
899 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
900 body.ApplyTorqueImpulse(ref fSum);
901 }
902
903 public override void DestroyObject(BulletWorld pWorld, BulletBody pBody)
904 {
905 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
906 CollisionObject co = (pBody as BulletBodyXNA).rigidBody;
907 RigidBody bo = co as RigidBody;
908 if (bo == null)
909 {
910
911 if (world.IsInWorld(co))
912 {
913 world.RemoveCollisionObject(co);
914 }
915 }
916 else
917 {
918
919 if (world.IsInWorld(bo))
920 {
921 world.RemoveRigidBody(bo);
922 }
923 }
924 if (co != null)
925 {
926 if (co.GetUserPointer() != null)
927 {
928 uint localId = (uint) co.GetUserPointer();
929 if (specialCollisionObjects.ContainsKey(localId))
930 {
931 specialCollisionObjects.Remove(localId);
932 }
933 }
934 }
935
936 }
937
938 public override void Shutdown(BulletWorld pWorld)
939 {
940 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
941 world.Cleanup();
942 }
943
944 public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id)
945 {
946 CollisionShape shape1 = (pShape as BulletShapeXNA).shape;
947
948 // TODO: Turn this from a reference copy to a Value Copy.
949 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
950
951 return shape2;
952 }
953
954 public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape)
955 {
956 //TODO:
957 return false;
958 }
959 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
960
961 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
962 {
963 CollisionWorld world = (pWorld as BulletWorldXNA).world;
964 IndexedMatrix mat =
965 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
966 pRawOrientation.Z, pRawOrientation.W));
967 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
968 CollisionShape shape = (pShape as BulletShapeXNA).shape;
969 //UpdateSingleAabb(world, shape);
970 // TODO: Feed Update array into null
971 SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null);
972 RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero);
973 RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero)
974 {
975 m_mass = 0
976 };
977 /*
978 m_mass = mass;
979 m_motionState =motionState;
980 m_collisionShape = collisionShape;
981 m_localInertia = localInertia;
982 m_linearDamping = 0f;
983 m_angularDamping = 0f;
984 m_friction = 0.5f;
985 m_restitution = 0f;
986 m_linearSleepingThreshold = 0.8f;
987 m_angularSleepingThreshold = 1f;
988 m_additionalDamping = false;
989 m_additionalDampingFactor = 0.005f;
990 m_additionalLinearDampingThresholdSqr = 0.01f;
991 m_additionalAngularDampingThresholdSqr = 0.01f;
992 m_additionalAngularDampingFactor = 0.01f;
993 m_startWorldTransform = IndexedMatrix.Identity;
994 */
995 body.SetUserPointer(pLocalID);
996
997 return new BulletBodyXNA(pLocalID, body);
998 }
999
1000
1001 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1002 {
1003
1004 IndexedMatrix mat =
1005 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
1006 pRawOrientation.Z, pRawOrientation.W));
1007 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1008
1009 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1010
1011 // TODO: Feed Update array into null
1012 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
1013 body.SetWorldTransform(mat);
1014 body.SetUserPointer(pLocalID);
1015 return new BulletBodyXNA(pLocalID, body);
1016 }
1017 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
1018 public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags)
1019 {
1020 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1021 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
1022 return (CollisionFlags)collisionObject.GetCollisionFlags();
1023 }
1024
1025 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
1026 {
1027
1028 /* TODO */
1029 return Vector3.Zero;
1030 }
1031 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
1032 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
1033 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
1034 public override bool IsStaticObject(BulletBody pCollisionObject)
1035 {
1036 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1037 return collisionObject.IsStaticObject();
1038
1039 }
1040 public override bool IsKinematicObject(BulletBody pCollisionObject)
1041 {
1042 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1043 return collisionObject.IsKinematicObject();
1044 }
1045 public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject)
1046 {
1047 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1048 return collisionObject.IsStaticOrKinematicObject();
1049 }
1050 public override bool HasContactResponse(BulletBody pCollisionObject)
1051 {
1052 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1053 return collisionObject.HasContactResponse();
1054 }
1055 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
1056 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
1057 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
1058 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
1059 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
1060 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
1061 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
1062 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
1063
1064 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
1065 public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction)
1066 {
1067 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1068 collisionObject.SetHitFraction(pHitFraction);
1069 }
1070 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
1071 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
1072 {
1073 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1074 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
1075 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
1076 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
1077 capsuleShapeZ.SetLocalScaling(ref scale);
1078
1079 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
1080 }
1081
1082 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
1083 int maxCollisions, ref CollisionDesc[] collisionArray,
1084 int maxUpdates, ref EntityProperties[] updateArray
1085 )
1086 {
1087
1088 UpdatedObjects = updateArray;
1089 UpdatedCollisions = collisionArray;
1090 /* TODO */
1091 ConfigurationParameters[] configparms = new ConfigurationParameters[1];
1092 configparms[0] = parms;
1093 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
1094 m_maxCollisions = maxCollisions;
1095 m_maxUpdatesPerFrame = maxUpdates;
1096 specialCollisionObjects = new Dictionary<uint, GhostObject>();
1097
1098 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1099 }
1100
1101 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1102 ConfigurationParameters[] o,
1103 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1104 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1105 object mDebugLogCallbackHandle)
1106 {
1107 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
1108
1109 p.angularDamping = BSParam.AngularDamping;
1110 p.defaultFriction = o[0].defaultFriction;
1111 p.defaultFriction = o[0].defaultFriction;
1112 p.defaultDensity = o[0].defaultDensity;
1113 p.defaultRestitution = o[0].defaultRestitution;
1114 p.collisionMargin = o[0].collisionMargin;
1115 p.gravity = o[0].gravity;
1116
1117 p.linearDamping = BSParam.LinearDamping;
1118 p.angularDamping = BSParam.AngularDamping;
1119 p.deactivationTime = BSParam.DeactivationTime;
1120 p.linearSleepingThreshold = BSParam.LinearSleepingThreshold;
1121 p.angularSleepingThreshold = BSParam.AngularSleepingThreshold;
1122 p.ccdMotionThreshold = BSParam.CcdMotionThreshold;
1123 p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius;
1124 p.contactProcessingThreshold = BSParam.ContactProcessingThreshold;
1125
1126 p.terrainImplementation = BSParam.TerrainImplementation;
1127 p.terrainFriction = BSParam.TerrainFriction;
1128
1129 p.terrainHitFraction = BSParam.TerrainHitFraction;
1130 p.terrainRestitution = BSParam.TerrainRestitution;
1131 p.terrainCollisionMargin = BSParam.TerrainCollisionMargin;
1132
1133 p.avatarFriction = BSParam.AvatarFriction;
1134 p.avatarStandingFriction = BSParam.AvatarStandingFriction;
1135 p.avatarDensity = BSParam.AvatarDensity;
1136 p.avatarRestitution = BSParam.AvatarRestitution;
1137 p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth;
1138 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
1139 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
1140 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
1141
1142 p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
1143
1144 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1145 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1146 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
1147 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
1148 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
1149 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
1150 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
1151 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
1152
1153 p.linksetImplementation = BSParam.LinksetImplementation;
1154 p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset);
1155 p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor);
1156 p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
1157 p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
1158 p.linkConstraintERP = BSParam.LinkConstraintERP;
1159 p.linkConstraintCFM = BSParam.LinkConstraintCFM;
1160 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
1161 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
1162 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1163
1164 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1165 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1166
1167
1168 if (p.maxPersistantManifoldPoolSize > 0)
1169 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
1170 if (p.shouldDisableContactPoolDynamicAllocation !=0)
1171 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
1172 //if (p.maxCollisionAlgorithmPoolSize >0 )
1173
1174 DbvtBroadphase m_broadphase = new DbvtBroadphase();
1175 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
1176 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
1177
1178 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
1179 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
1180
1181 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
1182
1183 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
1184
1185 world.LastCollisionDesc = 0;
1186 world.LastEntityProperty = 0;
1187
1188 world.WorldSettings.Params = p;
1189 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
1190 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
1191 if (p.shouldRandomizeSolverOrder != 0)
1192 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
1193
1194 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
1195 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
1196
1197 if (p.shouldEnableFrictionCaching != 0)
1198 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1199
1200 if (p.numberOfSolverIterations > 0)
1201 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
1202
1203
1204 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
1205 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
1206 world.GetSolverInfo().m_globalCfm = 0.0f;
1207 world.GetSolverInfo().m_tau = 0.6f;
1208 world.GetSolverInfo().m_friction = 0.3f;
1209 world.GetSolverInfo().m_maxErrorReduction = 20f;
1210 world.GetSolverInfo().m_numIterations = 10;
1211 world.GetSolverInfo().m_erp = 0.2f;
1212 world.GetSolverInfo().m_erp2 = 0.1f;
1213 world.GetSolverInfo().m_sor = 1.0f;
1214 world.GetSolverInfo().m_splitImpulse = false;
1215 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1216 world.GetSolverInfo().m_linearSlop = 0.0f;
1217 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1218 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1219 world.SetForceUpdateAllAabbs(true);
1220
1221 //BSParam.TerrainImplementation = 0;
1222 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1223
1224 return world;
1225 }
1226 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1227 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1228 {
1229 Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
1230 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1231 {
1232 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1233 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1234 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1235 }
1236 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1237 {
1238 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1239 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1240 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1241 }
1242 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1243 {
1244 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1245 }
1246 return true;
1247 }
1248
1249 public override bool PushUpdate(BulletBody pCollisionObject)
1250 {
1251 bool ret = false;
1252 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1253 RigidBody rb = collisionObject as RigidBody;
1254 if (rb != null)
1255 {
1256 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1257 if (sms != null)
1258 {
1259 IndexedMatrix wt = IndexedMatrix.Identity;
1260 sms.GetWorldTransform(out wt);
1261 sms.SetWorldTransform(ref wt, true);
1262 ret = true;
1263 }
1264 }
1265 return ret;
1266
1267 }
1268
1269 public override float GetAngularMotionDisc(BulletShape pShape)
1270 {
1271 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1272 return shape.GetAngularMotionDisc();
1273 }
1274 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1275 {
1276 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1277 return shape.GetContactBreakingThreshold(defaultFactor);
1278 }
1279 public override bool IsCompound(BulletShape pShape)
1280 {
1281 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1282 return shape.IsCompound();
1283 }
1284 public override bool IsSoftBody(BulletShape pShape)
1285 {
1286 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1287 return shape.IsSoftBody();
1288 }
1289 public override bool IsPolyhedral(BulletShape pShape)
1290 {
1291 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1292 return shape.IsPolyhedral();
1293 }
1294 public override bool IsConvex2d(BulletShape pShape)
1295 {
1296 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1297 return shape.IsConvex2d();
1298 }
1299 public override bool IsConvex(BulletShape pShape)
1300 {
1301 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1302 return shape.IsConvex();
1303 }
1304 public override bool IsNonMoving(BulletShape pShape)
1305 {
1306 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1307 return shape.IsNonMoving();
1308 }
1309 public override bool IsConcave(BulletShape pShape)
1310 {
1311 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1312 return shape.IsConcave();
1313 }
1314 public override bool IsInfinite(BulletShape pShape)
1315 {
1316 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1317 return shape.IsInfinite();
1318 }
1319 public override bool IsNativeShape(BulletShape pShape)
1320 {
1321 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1322 bool ret;
1323 switch (shape.GetShapeType())
1324 {
1325 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1326 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1327 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1328 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1329 ret = true;
1330 break;
1331 default:
1332 ret = false;
1333 break;
1334 }
1335 return ret;
1336 }
1337
1338 public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin)
1339 {
1340 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1341 shape.SetMargin(pMargin);
1342 }
1343
1344 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1345 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1346 {
1347 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1348 IndexedMatrix bodyTransform = new IndexedMatrix();
1349 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1350 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1351 GhostObject gObj = new PairCachingGhostObject();
1352 gObj.SetWorldTransform(bodyTransform);
1353 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1354 gObj.SetCollisionShape(shape);
1355 gObj.SetUserPointer(pLocalID);
1356
1357 if (specialCollisionObjects.ContainsKey(pLocalID))
1358 specialCollisionObjects[pLocalID] = gObj;
1359 else
1360 specialCollisionObjects.Add(pLocalID, gObj);
1361
1362 // TODO: Add to Special CollisionObjects!
1363 return new BulletBodyXNA(pLocalID, gObj);
1364 }
1365
1366 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape)
1367 {
1368 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1369 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1370 if (pShape == null)
1371 {
1372 collisionObject.SetCollisionShape(new EmptyShape());
1373 }
1374 else
1375 {
1376 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1377 collisionObject.SetCollisionShape(shape);
1378 }
1379 }
1380 public override BulletShape GetCollisionShape(BulletBody pCollisionObject)
1381 {
1382 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1383 CollisionShape shape = collisionObject.GetCollisionShape();
1384 return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1385 }
1386
1387 //(PhysicsScene.World.ptr, nativeShapeData)
1388 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1389 {
1390 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1391 CollisionShape shape = null;
1392 switch (pShapeData.Type)
1393 {
1394 case BSPhysicsShapeType.SHAPE_BOX:
1395 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1396 break;
1397 case BSPhysicsShapeType.SHAPE_CONE:
1398 shape = new ConeShapeZ(0.5f, 1.0f);
1399 break;
1400 case BSPhysicsShapeType.SHAPE_CYLINDER:
1401 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1402 break;
1403 case BSPhysicsShapeType.SHAPE_SPHERE:
1404 shape = new SphereShape(0.5f);
1405 break;
1406
1407 }
1408 if (shape != null)
1409 {
1410 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1411 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1412 shape.SetLocalScaling(ref scaling);
1413
1414 }
1415 return new BulletShapeXNA(shape, pShapeData.Type);
1416 }
1417 //PhysicsScene.World.ptr, false
1418 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1419 {
1420 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1421 }
1422
1423 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1424 {
1425 CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
1426 return compoundshape.GetNumChildShapes();
1427 }
1428 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1429 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1430 {
1431 IndexedMatrix relativeTransform = new IndexedMatrix();
1432 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1433 CollisionShape addshape = (paddShape as BulletShapeXNA).shape;
1434
1435 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1436 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1437 compoundshape.AddChildShape(ref relativeTransform, addshape);
1438
1439 }
1440
1441 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1442 {
1443 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1444 CollisionShape ret = null;
1445 ret = compoundshape.GetChildShape(pii);
1446 compoundshape.RemoveChildShapeByIndex(pii);
1447 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
1448 }
1449
1450 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
1451
1452 if (cShape == null)
1453 return null;
1454 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
1455 CollisionShape shape = compoundShape.GetChildShape(indx);
1456 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1457
1458
1459 return retShape;
1460 }
1461
1462 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
1463 {
1464 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1465 switch (pin)
1466 {
1467 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1468 ret = BSPhysicsShapeType.SHAPE_BOX;
1469 break;
1470 case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE:
1471 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1472 break;
1473
1474 case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE:
1475 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1476 break;
1477 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE:
1478 ret = BSPhysicsShapeType.SHAPE_MESH;
1479 break;
1480 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE:
1481 ret = BSPhysicsShapeType.SHAPE_HULL;
1482 break;
1483 case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE:
1484 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1485 break;
1486 case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE:
1487 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1488 break;
1489 //implicit convex shapes
1490 case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE:
1491 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1492 break;
1493 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1494 ret = BSPhysicsShapeType.SHAPE_SPHERE;
1495 break;
1496 case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE:
1497 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1498 break;
1499 case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE:
1500 ret = BSPhysicsShapeType.SHAPE_CAPSULE;
1501 break;
1502 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1503 ret = BSPhysicsShapeType.SHAPE_CONE;
1504 break;
1505 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE:
1506 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1507 break;
1508 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1509 ret = BSPhysicsShapeType.SHAPE_CYLINDER;
1510 break;
1511 case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE:
1512 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1513 break;
1514 case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE:
1515 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1516 break;
1517 case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE:
1518 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1519 break;
1520 case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE:
1521 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1522 break;
1523 case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE:
1524 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1525 break;
1526 case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE:
1527 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1528 break;
1529 //concave shape
1530 case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE:
1531 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1532 break;
1533 //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy!
1534 case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE:
1535 ret = BSPhysicsShapeType.SHAPE_MESH;
1536 break;
1537 case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE:
1538 ret = BSPhysicsShapeType.SHAPE_MESH;
1539 break;
1540 ///used for demo integration FAST/Swift collision library and Bullet
1541 case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE:
1542 ret = BSPhysicsShapeType.SHAPE_MESH;
1543 break;
1544 //terrain
1545 case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE:
1546 ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP;
1547 break;
1548 ///Used for GIMPACT Trimesh integration
1549 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE:
1550 ret = BSPhysicsShapeType.SHAPE_MESH;
1551 break;
1552 ///Multimaterial mesh
1553 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE:
1554 ret = BSPhysicsShapeType.SHAPE_MESH;
1555 break;
1556
1557 case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE:
1558 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1559 break;
1560 case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE:
1561 ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE;
1562 break;
1563 case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE:
1564 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1565 break;
1566 case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE:
1567 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1568 break;
1569
1570 case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE:
1571 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
1572 break;
1573
1574 case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE:
1575 ret = BSPhysicsShapeType.SHAPE_MESH;
1576 break;
1577 case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE:
1578 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1579 break;
1580 case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE:
1581 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1582 break;
1583 case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE:
1584 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1585 break;
1586 }
1587 return ret;
1588 }
1589
1590 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1591 public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ }
1592
1593 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1594 {
1595 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1596 m_planeshape.SetMargin(pcollisionMargin);
1597 m_planeshape.SetUserPointer(pLocalId);
1598 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1599 }
1600
1601 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1602 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
1603 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1604
1605 {
1606 Generic6DofSpringConstraint constrain = null;
1607 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1608 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
1609 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
1610 if (body1 != null && body2 != null)
1611 {
1612 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1613 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1614 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1615 frame1._origin = frame1v;
1616
1617 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1618 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1619 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1620 frame2._origin = frame1v;
1621
1622 constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1623 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1624
1625 constrain.CalculateTransforms();
1626 }
1627
1628 return new BulletConstraintXNA(constrain);
1629 }
1630
1631 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1632 Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB,
1633 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1634 {
1635 HingeConstraint constrain = null;
1636 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1637 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1638 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1639 if (rb1 != null && rb2 != null)
1640 {
1641 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1642 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1643 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1644 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1645 constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA);
1646 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1647 }
1648 return new BulletConstraintXNA(constrain);
1649 }
1650
1651 public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1652 Vector3 pframe1, Quaternion pframe1rot,
1653 Vector3 pframe2, Quaternion pframe2rot,
1654 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1655 {
1656 SliderConstraint constrain = null;
1657 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1658 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1659 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1660 if (rb1 != null && rb2 != null)
1661 {
1662 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1663 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1664 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1665 frame1._origin = frame1v;
1666
1667 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1668 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1669 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1670 frame2._origin = frame1v;
1671
1672 constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1673 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1674 }
1675 return new BulletConstraintXNA(constrain);
1676 }
1677
1678 public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1679 Vector3 pframe1, Quaternion pframe1rot,
1680 Vector3 pframe2, Quaternion pframe2rot,
1681 bool pdisableCollisionsBetweenLinkedBodies)
1682 {
1683 ConeTwistConstraint constrain = null;
1684 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1685 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1686 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1687 if (rb1 != null && rb2 != null)
1688 {
1689 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1690 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1691 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1692 frame1._origin = frame1v;
1693
1694 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1695 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1696 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1697 frame2._origin = frame1v;
1698
1699 constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2);
1700 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1701 }
1702 return new BulletConstraintXNA(constrain);
1703 }
1704
1705 public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1706 Vector3 paxisInA, Vector3 paxisInB,
1707 float pratio, bool pdisableCollisionsBetweenLinkedBodies)
1708 {
1709 Generic6DofConstraint constrain = null;
1710 /* BulletXNA does not have a gear constraint
1711 GearConstraint constrain = null;
1712 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1713 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1714 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1715 if (rb1 != null && rb2 != null)
1716 {
1717 IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1718 IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1719 constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio);
1720 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1721 }
1722 */
1723 return new BulletConstraintXNA(constrain);
1724 }
1725
1726 public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1727 Vector3 ppivotInA, Vector3 ppivotInB,
1728 bool pdisableCollisionsBetweenLinkedBodies)
1729 {
1730 Point2PointConstraint constrain = null;
1731 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1732 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1733 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1734 if (rb1 != null && rb2 != null)
1735 {
1736 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1737 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1738 constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB);
1739 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1740 }
1741 return new BulletConstraintXNA(constrain);
1742 }
1743
1744 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
1745 {
1746 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1747 CompoundShape compoundshape = new CompoundShape(false);
1748
1749 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1750 int ii = 1;
1751
1752 for (int i = 0; i < pHullCount; i++)
1753 {
1754 int vertexCount = (int) pConvHulls[ii];
1755
1756 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1757 IndexedMatrix childTrans = IndexedMatrix.Identity;
1758 childTrans._origin = centroid;
1759
1760 List<IndexedVector3> virts = new List<IndexedVector3>();
1761 int ender = ((ii + 4) + (vertexCount*3));
1762 for (int iii = ii + 4; iii < ender; iii+=3)
1763 {
1764
1765 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1766 }
1767 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1768 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1769 compoundshape.AddChildShape(ref childTrans, convexShape);
1770 ii += (vertexCount*3 + 4);
1771 }
1772
1773 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1774 }
1775
1776 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
1777 {
1778 /* TODO */ return null;
1779
1780 }
1781
1782 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1783 {
1784 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1785
1786 for (int iter = 0; iter < pVerticesCount; iter++)
1787 {
1788 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1789 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1790 }
1791
1792 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1793 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1794 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1795 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1796 IndexedMesh mesh = new IndexedMesh();
1797 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1798 mesh.m_numTriangles = pIndicesCount/3;
1799 mesh.m_numVertices = pVerticesCount;
1800 mesh.m_triangleIndexBase = indicesarr;
1801 mesh.m_vertexBase = vertices;
1802 mesh.m_vertexStride = 3;
1803 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1804 mesh.m_triangleIndexStride = 3;
1805
1806 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1807 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1808 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1809 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1810 // world.UpdateSingleAabb(meshShape);
1811 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1812
1813 }
1814 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1815 {
1816
1817 String fileName = "objTest3.raw";
1818 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1819 StreamWriter sw = new StreamWriter(completePath);
1820 IndexedMesh mesh = new IndexedMesh();
1821
1822 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1823 mesh.m_numTriangles = pIndicesCount / 3;
1824 mesh.m_numVertices = pVerticesCount;
1825 mesh.m_triangleIndexBase = indices;
1826 mesh.m_vertexBase = vertices;
1827 mesh.m_vertexStride = 3;
1828 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1829 mesh.m_triangleIndexStride = 3;
1830
1831 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1832 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1833
1834
1835
1836 for (int i = 0; i < pVerticesCount; i++)
1837 {
1838
1839 string s = vertices[indices[i * 3]].ToString("0.0000");
1840 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1841 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1842
1843 sw.Write(s + "\n");
1844 }
1845
1846 sw.Close();
1847 }
1848 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1849 {
1850
1851 String fileName = "objTest6.raw";
1852 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1853 StreamWriter sw = new StreamWriter(completePath);
1854 IndexedMesh mesh = new IndexedMesh();
1855
1856 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1857 mesh.m_numTriangles = pIndicesCount / 3;
1858 mesh.m_numVertices = pVerticesCount;
1859 mesh.m_triangleIndexBase = indices;
1860 mesh.m_vertexBase = vertices;
1861 mesh.m_vertexStride = 3;
1862 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1863 mesh.m_triangleIndexStride = 3;
1864
1865 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1866 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1867
1868
1869 sw.WriteLine("Indices");
1870 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1871 for (int iter = 0; iter < indices.Length; iter++)
1872 {
1873 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1874 }
1875 sw.WriteLine("VerticesFloats");
1876 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1877 for (int iter = 0; iter < vertices.Length; iter++)
1878 {
1879 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1880 }
1881
1882 // for (int i = 0; i < pVerticesCount; i++)
1883 // {
1884 //
1885 // string s = vertices[indices[i * 3]].ToString("0.0000");
1886 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1887 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1888 //
1889 // sw.Write(s + "\n");
1890 //}
1891
1892 sw.Close();
1893 }
1894
1895 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1896 float scaleFactor, float collisionMargin)
1897 {
1898 const int upAxis = 2;
1899 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
1900 heightMap, scaleFactor,
1901 minHeight, maxHeight, upAxis,
1902 false);
1903 terrainShape.SetMargin(collisionMargin + 0.5f);
1904 terrainShape.SetUseDiamondSubdivision(true);
1905 terrainShape.SetUserPointer(id);
1906 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
1907 }
1908
1909 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1910 {
1911 TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain;
1912 bool onOff = ponOff != 0;
1913 bool ret = false;
1914
1915 switch (tconstrain.GetConstraintType())
1916 {
1917 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1918 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
1919 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1920 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1921 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1922 ret = true;
1923 break;
1924 }
1925
1926
1927 return ret;
1928
1929 }
1930
1931 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
1932 out int updatedEntityCount, out int collidersCount)
1933 {
1934 /* TODO */
1935 updatedEntityCount = 0;
1936 collidersCount = 0;
1937
1938
1939 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
1940
1941 return ret;
1942 }
1943
1944 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1945 out int updatedEntityCount, out EntityProperties[] updatedEntities,
1946 out int collidersCount, out CollisionDesc[] colliders)
1947 {
1948 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1949 out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame);
1950 return epic;
1951 }
1952
1953 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
1954 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
1955 {
1956 int numSimSteps = 0;
1957 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
1958 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
1959 LastEntityProperty=0;
1960
1961
1962
1963
1964
1965
1966 LastCollisionDesc=0;
1967
1968 updatedEntityCount = 0;
1969 collidersCount = 0;
1970
1971
1972 if (pWorld is BulletWorldXNA)
1973 {
1974 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1975
1976 world.LastCollisionDesc = 0;
1977 world.LastEntityProperty = 0;
1978 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1979 int updates = 0;
1980
1981 PersistentManifold contactManifold;
1982 CollisionObject objA;
1983 CollisionObject objB;
1984 ManifoldPoint manifoldPoint;
1985 PairCachingGhostObject pairCachingGhostObject;
1986
1987 m_collisionsThisFrame = 0;
1988 int numManifolds = world.GetDispatcher().GetNumManifolds();
1989 for (int j = 0; j < numManifolds; j++)
1990 {
1991 contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1992 int numContacts = contactManifold.GetNumContacts();
1993 if (numContacts == 0)
1994 continue;
1995
1996 objA = contactManifold.GetBody0() as CollisionObject;
1997 objB = contactManifold.GetBody1() as CollisionObject;
1998
1999 manifoldPoint = contactManifold.GetContactPoint(0);
2000 //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
2001 // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
2002
2003 RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance());
2004 m_collisionsThisFrame ++;
2005 if (m_collisionsThisFrame >= 9999999)
2006 break;
2007
2008
2009 }
2010
2011 foreach (GhostObject ghostObject in specialCollisionObjects.Values)
2012 {
2013 pairCachingGhostObject = ghostObject as PairCachingGhostObject;
2014 if (pairCachingGhostObject != null)
2015 {
2016 RecordGhostCollisions(pairCachingGhostObject);
2017 }
2018
2019 }
2020
2021
2022 updatedEntityCount = LastEntityProperty;
2023 updatedEntities = UpdatedObjects;
2024
2025 collidersCount = LastCollisionDesc;
2026 colliders = UpdatedCollisions;
2027
2028
2029 }
2030 else
2031 {
2032 //if (updatedEntities is null)
2033 //updatedEntities = new List<BulletXNA.EntityProperties>();
2034 //updatedEntityCount = 0;
2035
2036
2037 //collidersCount = 0;
2038
2039 updatedEntities = new EntityProperties[0];
2040
2041
2042 colliders = new CollisionDesc[0];
2043
2044 }
2045 return numSimSteps;
2046 }
2047 public void RecordGhostCollisions(PairCachingGhostObject obj)
2048 {
2049 IOverlappingPairCache cache = obj.GetOverlappingPairCache();
2050 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray();
2051
2052 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
2053 PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
2054 BroadphasePair collisionPair;
2055 PersistentManifold contactManifold;
2056
2057 CollisionObject objA;
2058 CollisionObject objB;
2059
2060 ManifoldPoint pt;
2061
2062 int numPairs = pairs.Count;
2063
2064 for (int i = 0; i < numPairs; i++)
2065 {
2066 manifoldArray.Clear();
2067 if (LastCollisionDesc < UpdatedCollisions.Length)
2068 break;
2069 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
2070 if (collisionPair == null)
2071 continue;
2072
2073 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
2074 for (int j = 0; j < manifoldArray.Count; j++)
2075 {
2076 contactManifold = manifoldArray[j];
2077 int numContacts = contactManifold.GetNumContacts();
2078 objA = contactManifold.GetBody0() as CollisionObject;
2079 objB = contactManifold.GetBody1() as CollisionObject;
2080 for (int p = 0; p < numContacts; p++)
2081 {
2082 pt = contactManifold.GetContactPoint(p);
2083 if (pt.GetDistance() < 0.0f)
2084 {
2085 RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance());
2086 break;
2087 }
2088 }
2089 }
2090 }
2091
2092 }
2093 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
2094 {
2095
2096 IndexedVector3 contactNormal = norm;
2097 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
2098 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
2099 {
2100 return;
2101 }
2102 uint idA = (uint)objA.GetUserPointer();
2103 uint idB = (uint)objB.GetUserPointer();
2104 if (idA > idB)
2105 {
2106 uint temp = idA;
2107 idA = idB;
2108 idB = temp;
2109 contactNormal = -contactNormal;
2110 }
2111
2112 //ulong collisionID = ((ulong) idA << 32) | idB;
2113
2114 CollisionDesc cDesc = new CollisionDesc()
2115 {
2116 aID = idA,
2117 bID = idB,
2118 point = new Vector3(contact.X,contact.Y,contact.Z),
2119 normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z),
2120 penetration = penetration
2121
2122 };
2123 if (world.LastCollisionDesc < world.UpdatedCollisions.Length)
2124 world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc);
2125 m_collisionsThisFrame++;
2126
2127
2128 }
2129 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject)
2130 {
2131 EntityProperties ent = new EntityProperties();
2132 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2133 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
2134 IndexedMatrix transform = collisionObject.GetWorldTransform();
2135 IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity();
2136 IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity();
2137 IndexedQuaternion rotation = transform.GetRotation();
2138 ent.Acceleration = Vector3.Zero;
2139 ent.ID = (uint)collisionObject.GetUserPointer();
2140 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
2141 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
2142 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
2143 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
2144 return ent;
2145 }
2146
2147 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */
2148 return false; }
2149
2150 public override Vector3 GetLocalScaling(BulletShape pShape)
2151 {
2152 CollisionShape shape = (pShape as BulletShapeXNA).shape;
2153 IndexedVector3 scale = shape.GetLocalScaling();
2154 return new Vector3(scale.X,scale.Y,scale.Z);
2155 }
2156
2157 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
2158 {
2159 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2160 if (world != null)
2161 {
2162 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
2163 {
2164 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
2165
2166 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
2167 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
2168 using (
2169 ClosestNotMeRayResultCallback rayCallback =
2170 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
2171 )
2172 {
2173 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
2174 if (rayCallback.HasHit())
2175 {
2176 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
2177 }
2178 return rayCallback.HasHit();
2179 }
2180 }
2181 }
2182 return false;
2183 }
2184}
2185
2186
2187
2188
2189 public class SimMotionState : DefaultMotionState
2190 {
2191 public RigidBody Rigidbody;
2192 public Vector3 ZeroVect;
2193
2194 private IndexedMatrix m_xform;
2195
2196 private EntityProperties m_properties;
2197 private EntityProperties m_lastProperties;
2198 private BSAPIXNA m_world;
2199
2200 const float POSITION_TOLERANCE = 0.05f;
2201 const float VELOCITY_TOLERANCE = 0.001f;
2202 const float ROTATION_TOLERANCE = 0.01f;
2203 const float ANGULARVELOCITY_TOLERANCE = 0.01f;
2204
2205 public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates)
2206 {
2207 IndexedQuaternion OrientationQuaterion = starTransform.GetRotation();
2208 m_properties = new EntityProperties()
2209 {
2210 ID = id,
2211 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z),
2212 Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W)
2213 };
2214 m_lastProperties = new EntityProperties()
2215 {
2216 ID = id,
2217 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z),
2218 Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W)
2219 };
2220 m_world = pWorld;
2221 m_xform = starTransform;
2222 }
2223
2224 public override void GetWorldTransform(out IndexedMatrix worldTrans)
2225 {
2226 worldTrans = m_xform;
2227 }
2228
2229 public override void SetWorldTransform(IndexedMatrix worldTrans)
2230 {
2231 SetWorldTransform(ref worldTrans);
2232 }
2233
2234 public override void SetWorldTransform(ref IndexedMatrix worldTrans)
2235 {
2236 SetWorldTransform(ref worldTrans, false);
2237 }
2238 public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force)
2239 {
2240 m_xform = worldTrans;
2241 // Put the new transform into m_properties
2242 IndexedQuaternion OrientationQuaternion = m_xform.GetRotation();
2243 IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity();
2244 IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity();
2245 m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z);
2246 m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y,
2247 OrientationQuaternion.Z, OrientationQuaternion.W);
2248 // A problem with stock Bullet is that we don't get an event when an object is deactivated.
2249 // This means that the last non-zero values for linear and angular velocity
2250 // are left in the viewer who does dead reconning and the objects look like
2251 // they float off.
2252 // BulletSim ships with a patch to Bullet which creates such an event.
2253 m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z);
2254 m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z);
2255
2256 if (force
2257
2258 || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE)
2259 || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE)
2260 // If the Velocity and AngularVelocity are zero, most likely the object has
2261 // been deactivated. If they both are zero and they have become zero recently,
2262 // make sure a property update is sent so the zeros make it to the viewer.
2263 || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect)
2264 &&
2265 (m_properties.Velocity != m_lastProperties.Velocity ||
2266 m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity))
2267 // If Velocity and AngularVelocity are non-zero but have changed, send an update.
2268 || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE)
2269 ||
2270 !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity,
2271 ANGULARVELOCITY_TOLERANCE)
2272 )
2273
2274
2275 {
2276 // Add this update to the list of updates for this frame.
2277 m_lastProperties = m_properties;
2278 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
2279 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
2280
2281 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
2282 }
2283
2284
2285
2286
2287 }
2288 public override void SetRigidBody(RigidBody body)
2289 {
2290 Rigidbody = body;
2291 }
2292 internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon)
2293 {
2294 return
2295 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2296 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2297 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon)));
2298 }
2299
2300 internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon)
2301 {
2302 return
2303 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2304 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2305 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
2306 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
2307 }
2308
2309 }
2310}
2311
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
new file mode 100644
index 0000000..5765b0d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -0,0 +1,683 @@
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 copyright
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 UInt32 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 UInt32 ID;
115 public float Fraction;
116 public Vector3 Normal;
117 public Vector3 Point;
118}
119[StructLayout(LayoutKind.Sequential)]
120public struct RaycastHit
121{
122 public UInt32 ID;
123 public float Fraction;
124 public Vector3 Normal;
125}
126[StructLayout(LayoutKind.Sequential)]
127public struct CollisionDesc
128{
129 public UInt32 aID;
130 public UInt32 bID;
131 public Vector3 point;
132 public Vector3 normal;
133 public float penetration;
134}
135[StructLayout(LayoutKind.Sequential)]
136public struct EntityProperties
137{
138 public UInt32 ID;
139 public Vector3 Position;
140 public Quaternion Rotation;
141 public Vector3 Velocity;
142 public Vector3 Acceleration;
143 public Vector3 RotationalVelocity;
144
145 public override string ToString()
146 {
147 StringBuilder buff = new StringBuilder();
148 buff.Append("<i=");
149 buff.Append(ID.ToString());
150 buff.Append(",p=");
151 buff.Append(Position.ToString());
152 buff.Append(",r=");
153 buff.Append(Rotation.ToString());
154 buff.Append(",v=");
155 buff.Append(Velocity.ToString());
156 buff.Append(",a=");
157 buff.Append(Acceleration.ToString());
158 buff.Append(",rv=");
159 buff.Append(RotationalVelocity.ToString());
160 buff.Append(">");
161 return buff.ToString();
162 }
163}
164
165// Format of this structure must match the definition in the C++ code
166// NOTE: adding the X causes compile breaks if used. These are unused symbols
167// that can be removed from both here and the unmanaged definition of this structure.
168[StructLayout(LayoutKind.Sequential)]
169public struct ConfigurationParameters
170{
171 public float defaultFriction;
172 public float defaultDensity;
173 public float defaultRestitution;
174 public float collisionMargin;
175 public float gravity;
176
177 public float maxPersistantManifoldPoolSize;
178 public float maxCollisionAlgorithmPoolSize;
179 public float shouldDisableContactPoolDynamicAllocation;
180 public float shouldForceUpdateAllAabbs;
181 public float shouldRandomizeSolverOrder;
182 public float shouldSplitSimulationIslands;
183 public float shouldEnableFrictionCaching;
184 public float numberOfSolverIterations;
185 public float useSingleSidedMeshes;
186 public float globalContactBreakingThreshold;
187
188 public float physicsLoggingFrames;
189
190 public const float numericTrue = 1f;
191 public const float numericFalse = 0f;
192}
193
194
195// The states a bullet collision object can have
196public enum ActivationState : uint
197{
198 ACTIVE_TAG = 1,
199 ISLAND_SLEEPING,
200 WANTS_DEACTIVATION,
201 DISABLE_DEACTIVATION,
202 DISABLE_SIMULATION,
203}
204
205public enum CollisionObjectTypes : int
206{
207 CO_COLLISION_OBJECT = 1 << 0,
208 CO_RIGID_BODY = 1 << 1,
209 CO_GHOST_OBJECT = 1 << 2,
210 CO_SOFT_BODY = 1 << 3,
211 CO_HF_FLUID = 1 << 4,
212 CO_USER_TYPE = 1 << 5,
213}
214
215// Values used by Bullet and BulletSim to control object properties.
216// Bullet's "CollisionFlags" has more to do with operations on the
217// object (if collisions happen, if gravity effects it, ...).
218public enum CollisionFlags : uint
219{
220 CF_STATIC_OBJECT = 1 << 0,
221 CF_KINEMATIC_OBJECT = 1 << 1,
222 CF_NO_CONTACT_RESPONSE = 1 << 2,
223 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
224 CF_CHARACTER_OBJECT = 1 << 4,
225 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
226 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
227 // Following used by BulletSim to control collisions and updates
228 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
229 BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
230 BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
231 BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
232 BS_NONE = 0,
233 BS_ALL = 0xFFFFFFFF
234};
235
236// Values f collisions groups and masks
237public enum CollisionFilterGroups : uint
238{
239 // Don't use the bit definitions!! Define the use in a
240 // filter/mask definition below. This way collision interactions
241 // are more easily found and debugged.
242 BNoneGroup = 0,
243 BDefaultGroup = 1 << 0, // 0001
244 BStaticGroup = 1 << 1, // 0002
245 BKinematicGroup = 1 << 2, // 0004
246 BDebrisGroup = 1 << 3, // 0008
247 BSensorTrigger = 1 << 4, // 0010
248 BCharacterGroup = 1 << 5, // 0020
249 BAllGroup = 0x000FFFFF,
250 // Filter groups defined by BulletSim
251 BGroundPlaneGroup = 1 << 10, // 0400
252 BTerrainGroup = 1 << 11, // 0800
253 BRaycastGroup = 1 << 12, // 1000
254 BSolidGroup = 1 << 13, // 2000
255 // BLinksetGroup = xx // a linkset proper is either static or dynamic
256 BLinksetChildGroup = 1 << 14, // 4000
257};
258
259// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
260// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
261public enum ConstraintParams : int
262{
263 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
264 BT_CONSTRAINT_STOP_ERP,
265 BT_CONSTRAINT_CFM,
266 BT_CONSTRAINT_STOP_CFM,
267};
268public enum ConstraintParamAxis : int
269{
270 AXIS_LINEAR_X = 0,
271 AXIS_LINEAR_Y,
272 AXIS_LINEAR_Z,
273 AXIS_ANGULAR_X,
274 AXIS_ANGULAR_Y,
275 AXIS_ANGULAR_Z,
276 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
277 AXIS_ANGULAR_ALL,
278 AXIS_ALL
279};
280
281public abstract class BSAPITemplate
282{
283// Returns the name of the underlying Bullet engine
284public abstract string BulletEngineName { get; }
285public abstract string BulletEngineVersion { get; protected set;}
286
287// Initialization and simulation
288public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
289 int maxCollisions, ref CollisionDesc[] collisionArray,
290 int maxUpdates, ref EntityProperties[] updateArray
291 );
292
293public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
294 out int updatedEntityCount, out int collidersCount);
295
296public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
297
298public abstract void Shutdown(BulletWorld sim);
299
300public abstract bool PushUpdate(BulletBody obj);
301
302// =====================================================================================
303// Mesh, hull, shape and body creation helper routines
304public abstract BulletShape CreateMeshShape(BulletWorld world,
305 int indicesCount, int[] indices,
306 int verticesCount, float[] vertices );
307
308public abstract BulletShape CreateHullShape(BulletWorld world,
309 int hullCount, float[] hulls);
310
311public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
312
313public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
314
315public abstract bool IsNativeShape(BulletShape shape);
316
317public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
318
319public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
320
321public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
322
323public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
324
325public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
326
327public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
328
329public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
330
331public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
332
333public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
334
335public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
336
337public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
338
339public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
340
341public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
342
343public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
344
345public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
346
347public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
348
349public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
350
351// =====================================================================================
352public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
353
354public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
355 float scaleFactor, float collisionMargin);
356
357// =====================================================================================
358// Constraint creation and helper routines
359public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
360 Vector3 frame1loc, Quaternion frame1rot,
361 Vector3 frame2loc, Quaternion frame2rot,
362 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
363
364public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
365 Vector3 joinPoint,
366 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
367
368public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
369 Vector3 frameInBloc, Quaternion frameInBrot,
370 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
371
372public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
373 Vector3 frame1loc, Quaternion frame1rot,
374 Vector3 frame2loc, Quaternion frame2rot,
375 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
376
377public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
378 Vector3 pivotinA, Vector3 pivotinB,
379 Vector3 axisInA, Vector3 axisInB,
380 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
381
382public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
383 Vector3 frameInAloc, Quaternion frameInArot,
384 Vector3 frameInBloc, Quaternion frameInBrot,
385 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
386
387public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
388 Vector3 frameInAloc, Quaternion frameInArot,
389 Vector3 frameInBloc, Quaternion frameInBrot,
390 bool disableCollisionsBetweenLinkedBodies);
391
392public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
393 Vector3 axisInA, Vector3 axisInB,
394 float ratio, bool disableCollisionsBetweenLinkedBodies);
395
396public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
397 Vector3 pivotInA, Vector3 pivotInB,
398 bool disableCollisionsBetweenLinkedBodies);
399
400public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
401
402public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
403
404public abstract bool SetFrames(BulletConstraint constrain,
405 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
406
407public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
408
409public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
410
411public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
412
413public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
414
415public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
416
417public abstract bool CalculateTransforms(BulletConstraint constrain);
418
419public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
420
421public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
422
423// =====================================================================================
424// btCollisionWorld entries
425public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
426
427public abstract void UpdateAabbs(BulletWorld world);
428
429public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
430
431public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
432
433// =====================================================================================
434// btDynamicsWorld entries
435// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
436public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
437
438public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
439
440public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
441
442public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
443// =====================================================================================
444// btCollisionObject entries
445public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
446
447public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
448
449public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
450
451public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
452
453public abstract float GetContactProcessingThreshold(BulletBody obj);
454
455public abstract bool IsStaticObject(BulletBody obj);
456
457public abstract bool IsKinematicObject(BulletBody obj);
458
459public abstract bool IsStaticOrKinematicObject(BulletBody obj);
460
461public abstract bool HasContactResponse(BulletBody obj);
462
463public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
464
465public abstract BulletShape GetCollisionShape(BulletBody obj);
466
467public abstract int GetActivationState(BulletBody obj);
468
469public abstract void SetActivationState(BulletBody obj, int state);
470
471public abstract void SetDeactivationTime(BulletBody obj, float dtime);
472
473public abstract float GetDeactivationTime(BulletBody obj);
474
475public abstract void ForceActivationState(BulletBody obj, ActivationState state);
476
477public abstract void Activate(BulletBody obj, bool forceActivation);
478
479public abstract bool IsActive(BulletBody obj);
480
481public abstract void SetRestitution(BulletBody obj, float val);
482
483public abstract float GetRestitution(BulletBody obj);
484
485public abstract void SetFriction(BulletBody obj, float val);
486
487public abstract float GetFriction(BulletBody obj);
488
489public abstract Vector3 GetPosition(BulletBody obj);
490
491public abstract Quaternion GetOrientation(BulletBody obj);
492
493public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
494
495// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
496
497// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
498
499public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
500
501public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
502
503public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
504
505public abstract float GetHitFraction(BulletBody obj);
506
507public abstract void SetHitFraction(BulletBody obj, float val);
508
509public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
510
511public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
512
513public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
514
515public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
516
517public abstract float GetCcdMotionThreshold(BulletBody obj);
518
519public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
520
521public abstract float GetCcdSweptSphereRadius(BulletBody obj);
522
523public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
524
525public abstract IntPtr GetUserPointer(BulletBody obj);
526
527public abstract void SetUserPointer(BulletBody obj, IntPtr val);
528
529// =====================================================================================
530// btRigidBody entries
531public abstract void ApplyGravity(BulletBody obj);
532
533public abstract void SetGravity(BulletBody obj, Vector3 val);
534
535public abstract Vector3 GetGravity(BulletBody obj);
536
537public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
538
539public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
540
541public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
542
543public abstract float GetLinearDamping(BulletBody obj);
544
545public abstract float GetAngularDamping(BulletBody obj);
546
547public abstract float GetLinearSleepingThreshold(BulletBody obj);
548
549public abstract void ApplyDamping(BulletBody obj, float timeStep);
550
551public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
552
553public abstract Vector3 GetLinearFactor(BulletBody obj);
554
555public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
556
557public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
558
559// Add a force to the object as if its mass is one.
560public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
561
562// Set the force being applied to the object as if its mass is one.
563public abstract void SetObjectForce(BulletBody obj, Vector3 force);
564
565public abstract Vector3 GetTotalForce(BulletBody obj);
566
567public abstract Vector3 GetTotalTorque(BulletBody obj);
568
569public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
570
571public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
572
573public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
574
575public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
576
577// Apply force at the given point. Will add torque to the object.
578public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
579
580// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
581public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
582
583// Apply impulse to the object's torque. Force is scaled by object's mass.
584public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
585
586// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
587public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
588
589public abstract void ClearForces(BulletBody obj);
590
591public abstract void ClearAllForces(BulletBody obj);
592
593public abstract void UpdateInertiaTensor(BulletBody obj);
594
595public abstract Vector3 GetLinearVelocity(BulletBody obj);
596
597public abstract Vector3 GetAngularVelocity(BulletBody obj);
598
599public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
600
601public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
602
603public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
604
605public abstract void Translate(BulletBody obj, Vector3 trans);
606
607public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
608
609public abstract bool WantsSleeping(BulletBody obj);
610
611public abstract void SetAngularFactor(BulletBody obj, float factor);
612
613public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
614
615public abstract Vector3 GetAngularFactor(BulletBody obj);
616
617public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
618
619public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
620
621public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
622
623public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
624
625public abstract int GetNumConstraintRefs(BulletBody obj);
626
627public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask);
628
629// =====================================================================================
630// btCollisionShape entries
631
632public abstract float GetAngularMotionDisc(BulletShape shape);
633
634public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
635
636public abstract bool IsPolyhedral(BulletShape shape);
637
638public abstract bool IsConvex2d(BulletShape shape);
639
640public abstract bool IsConvex(BulletShape shape);
641
642public abstract bool IsNonMoving(BulletShape shape);
643
644public abstract bool IsConcave(BulletShape shape);
645
646public abstract bool IsCompound(BulletShape shape);
647
648public abstract bool IsSoftBody(BulletShape shape);
649
650public abstract bool IsInfinite(BulletShape shape);
651
652public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
653
654public abstract Vector3 GetLocalScaling(BulletShape shape);
655
656public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
657
658public abstract int GetShapeType(BulletShape shape);
659
660public abstract void SetMargin(BulletShape shape, float val);
661
662public abstract float GetMargin(BulletShape shape);
663
664// =====================================================================================
665// Debugging
666public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
667
668public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
669
670public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
671
672public virtual void DumpActivationInfo(BulletWorld sim) { }
673
674public virtual void DumpAllInfo(BulletWorld sim) { }
675
676public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
677
678public virtual void ResetBroadphasePool(BulletWorld sim) { }
679
680public virtual void ResetConstraintSolver(BulletWorld sim) { }
681
682};
683}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..90c2d9c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -45,7 +45,6 @@ public sealed class BSCharacter : BSPhysObject
45 private bool _selected; 45 private bool _selected;
46 private OMV.Vector3 _position; 46 private OMV.Vector3 _position;
47 private float _mass; 47 private float _mass;
48 private float _avatarDensity;
49 private float _avatarVolume; 48 private float _avatarVolume;
50 private OMV.Vector3 _force; 49 private OMV.Vector3 _force;
51 private OMV.Vector3 _velocity; 50 private OMV.Vector3 _velocity;
@@ -58,16 +57,12 @@ public sealed class BSCharacter : BSPhysObject
58 private bool _flying; 57 private bool _flying;
59 private bool _setAlwaysRun; 58 private bool _setAlwaysRun;
60 private bool _throttleUpdates; 59 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater; 60 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity; 61 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic; 62 private bool _kinematic;
66 private float _buoyancy; 63 private float _buoyancy;
67 64
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 65 private BSVMotor _velocityMotor;
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71 66
72 private OMV.Vector3 _PIDTarget; 67 private OMV.Vector3 _PIDTarget;
73 private bool _usePID; 68 private bool _usePID;
@@ -83,34 +78,36 @@ public sealed class BSCharacter : BSPhysObject
83 _physicsActorType = (int)ActorTypes.Agent; 78 _physicsActorType = (int)ActorTypes.Agent;
84 _position = pos; 79 _position = pos;
85 80
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; 81 _flying = isFlying;
93 _orientation = OMV.Quaternion.Identity; 82 _orientation = OMV.Quaternion.Identity;
94 _velocity = OMV.Vector3.Zero; 83 _velocity = OMV.Vector3.Zero;
95 _appliedVelocity = OMV.Vector3.Zero;
96 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 84 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
97 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 85 Friction = BSParam.AvatarStandingFriction;
98 _avatarDensity = PhysicsScene.Params.avatarDensity; 86 Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
87
88 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
89 // replace with the default values.
90 _size = size;
91 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
92 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
99 93
100 // The dimensions of the avatar capsule are kept in the scale. 94 // The dimensions of the physical capsule are kept in the scale.
101 // Physics creates a unit capsule which is scaled by the physics engine. 95 // Physics creates a unit capsule which is scaled by the physics engine.
102 ComputeAvatarScale(_size); 96 Scale = ComputeAvatarScale(_size);
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 97 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 98 ComputeAvatarVolumeAndMass();
99
100 SetupMovementMotor();
101
105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 102 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 103 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
107 104
108 // do actual create at taint time 105 // do actual creation in taint time
109 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 106 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
110 { 107 {
111 DetailLog("{0},BSCharacter.create,taint", LocalID); 108 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape 109 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); 110 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
114 111
115 SetPhysicalProperties(); 112 SetPhysicalProperties();
116 }); 113 });
@@ -120,54 +117,216 @@ public sealed class BSCharacter : BSPhysObject
120 // called when this character is being destroyed and the resources should be released 117 // called when this character is being destroyed and the resources should be released
121 public override void Destroy() 118 public override void Destroy()
122 { 119 {
120 base.Destroy();
121
123 DetailLog("{0},BSCharacter.Destroy", LocalID); 122 DetailLog("{0},BSCharacter.Destroy", LocalID);
124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 123 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
125 { 124 {
126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 125 PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 126 PhysBody.Clear();
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */);
128 PhysShape.Clear();
128 }); 129 });
129 } 130 }
130 131
131 private void SetPhysicalProperties() 132 private void SetPhysicalProperties()
132 { 133 {
133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 134 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
134 135
135 ZeroMotion(true); 136 ZeroMotion(true);
136 ForcePosition = _position; 137 ForcePosition = _position;
137 // Set the velocity and compute the proper friction 138
139 // Set the velocity
140 _velocityMotor.Reset();
141 _velocityMotor.SetTarget(_velocity);
142 _velocityMotor.SetCurrent(_velocity);
138 ForceVelocity = _velocity; 143 ForceVelocity = _velocity;
139 144
140 // This will enable or disable the flying buoyancy of the avatar. 145 // 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. 146 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying; 147 Flying = _flying;
143 148
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); 149 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); 150 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 151 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 152 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
148 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 153 if (BSParam.CcdMotionThreshold > 0f)
149 { 154 {
150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 155 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 156 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
152 } 157 }
153 158
154 UpdatePhysicalMassProperties(RawMass); 159 UpdatePhysicalMassProperties(RawMass, false);
155 160
156 // Make so capsule does not fall over 161 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); 162 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
158 163
159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 164 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
160 165
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 166 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
162 167
163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 168 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); 169 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 170 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
166 171
167 // Do this after the object has been added to the world 172 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, 173 PhysBody.collisionType = CollisionType.Avatar;
169 (uint)CollisionFilterGroups.AvatarFilter, 174 PhysBody.ApplyCollisionMask(PhysicsScene);
170 (uint)CollisionFilterGroups.AvatarMask); 175 }
176
177 // The avatar's movement is controlled by this motor that speeds up and slows down
178 // the avatar seeking to reach the motor's target speed.
179 // This motor runs as a prestep action for the avatar so it will keep the avatar
180 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
181 private void SetupMovementMotor()
182 {
183 // Infinite decay and timescale values so motor only changes current to target values.
184 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
185 0.2f, // time scale
186 BSMotor.Infinite, // decay time scale
187 BSMotor.InfiniteVector, // friction timescale
188 1f // efficiency
189 );
190 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
191
192 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
193 {
194 // TODO: Decide if the step parameters should be changed depending on the avatar's
195 // state (flying, colliding, ...). There is code in ODE to do this.
196
197 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
198 // specified for the avatar is the one that should be used. For falling, if the avatar
199 // is not flying and is not colliding then it is presumed to be falling and the Z
200 // component is not fooled with (thus allowing gravity to do its thing).
201 // When the avatar is standing, though, the user has specified a velocity of zero and
202 // the avatar should be standing. But if the avatar is pushed by something in the world
203 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
204 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
205 // errors can creap in and the avatar will slowly float off in some direction.
206 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
207 // from real pushing.
208 // The code below uses whether the collider is static or moving to decide whether to zero motion.
209
210 _velocityMotor.Step(timeStep);
211
212 // If we're not supposed to be moving, make sure things are zero.
213 if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero)
214 {
215 // The avatar shouldn't be moving
216 _velocityMotor.Zero();
217
218 if (IsColliding)
219 {
220 // If we are colliding with a stationary object, presume we're standing and don't move around
221 if (!ColliderIsMoving)
222 {
223 DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
224 ZeroMotion(true /* inTaintTime */);
225 }
226
227 // Standing has more friction on the ground
228 if (Friction != BSParam.AvatarStandingFriction)
229 {
230 Friction = BSParam.AvatarStandingFriction;
231 PhysicsScene.PE.SetFriction(PhysBody, Friction);
232 }
233 }
234 else
235 {
236 if (Flying)
237 {
238 // Flying and not collising and velocity nearly zero.
239 ZeroMotion(true /* inTaintTime */);
240 }
241 }
242
243 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
244 }
245 else
246 {
247 // Supposed to be moving.
248 OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
249
250 if (Friction != BSParam.AvatarFriction)
251 {
252 // Probably starting up walking. Set friction to moving friction.
253 Friction = BSParam.AvatarFriction;
254 PhysicsScene.PE.SetFriction(PhysBody, Friction);
255 }
256
257 // If falling, we keep the world's downward vector no matter what the other axis specify.
258 // The check for _velocity.Z < 0 makes jumping work (temporary upward force).
259 if (!Flying && !IsColliding)
260 {
261 if (_velocity.Z < 0)
262 stepVelocity.Z = _velocity.Z;
263 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
264 }
265
266 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
267 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
268
269 // Should we check for move force being small and forcing velocity to zero?
270
271 // Add special movement force to allow avatars to walk up stepped surfaces.
272 moveForce += WalkUpStairs();
273
274 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
275 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
276 }
277 });
278 }
279
280 // Decide if the character is colliding with a low object and compute a force to pop the
281 // avatar up so it can walk up and over the low objects.
282 private OMV.Vector3 WalkUpStairs()
283 {
284 OMV.Vector3 ret = OMV.Vector3.Zero;
285
286 // This test is done if moving forward, not flying and is colliding with something.
287 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
288 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
289 if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
290 {
291 // The range near the character's feet where we will consider stairs
292 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
293 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
294
295 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is
296 foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
297 {
298 // Don't care about collisions with the terrain
299 if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
300 {
301 OMV.Vector3 touchPosition = kvp.Value.Position;
302 // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
303 // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
304 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
305 {
306 // This contact is within the 'near the feet' range.
307 // The normal should be our contact point to the object so it is pointing away
308 // thus the difference between our facing orientation and the normal should be small.
309 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
310 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
311 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
312 if (diff < BSParam.AvatarStepApproachFactor)
313 {
314 // Found the stairs contact point. Push up a little to raise the character.
315 float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
316 ret = new OMV.Vector3(0f, 0f, upForce);
317
318 // Also move the avatar up for the new height
319 OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
320 ForcePosition = RawPosition + displacement;
321 }
322 DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
323 LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
324 }
325 }
326 }
327 }
328
329 return ret;
171 } 330 }
172 331
173 public override void RequestPhysicsterseUpdate() 332 public override void RequestPhysicsterseUpdate()
@@ -185,24 +344,31 @@ public sealed class BSCharacter : BSPhysObject
185 } 344 }
186 345
187 set { 346 set {
188 // When an avatar's size is set, only the height is changed.
189 _size = value; 347 _size = value;
190 ComputeAvatarScale(_size); 348 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
349 // replace with the default values.
350 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
351 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
352
353 Scale = ComputeAvatarScale(_size);
191 ComputeAvatarVolumeAndMass(); 354 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 355 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 356 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
194 357
195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 358 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
196 { 359 {
197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 360 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
198 UpdatePhysicalMassProperties(RawMass); 361 {
362 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
363 UpdatePhysicalMassProperties(RawMass, true);
364 // Make sure this change appears as a property update event
365 PhysicsScene.PE.PushUpdate(PhysBody);
366 }
199 }); 367 });
200 368
201 } 369 }
202 } 370 }
203 371
204 public override OMV.Vector3 Scale { get; set; }
205
206 public override PrimitiveBaseShape Shape 372 public override PrimitiveBaseShape Shape
207 { 373 {
208 set { BaseShape = value; } 374 set { BaseShape = value; }
@@ -219,6 +385,10 @@ public sealed class BSCharacter : BSPhysObject
219 public override bool Selected { 385 public override bool Selected {
220 set { _selected = value; } 386 set { _selected = value; }
221 } 387 }
388 public override bool IsSelected
389 {
390 get { return _selected; }
391 }
222 public override void CrossingFailure() { return; } 392 public override void CrossingFailure() { return; }
223 public override void link(PhysicsActor obj) { return; } 393 public override void link(PhysicsActor obj) { return; }
224 public override void delink() { return; } 394 public override void delink() { return; }
@@ -236,7 +406,8 @@ public sealed class BSCharacter : BSPhysObject
236 // Zero some other properties directly into the physics engine 406 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 407 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 { 408 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 409 if (PhysBody.HasPhysicalBody)
410 PhysicsScene.PE.ClearAllForces(PhysBody);
240 }); 411 });
241 } 412 }
242 public override void ZeroAngularMotion(bool inTaintTime) 413 public override void ZeroAngularMotion(bool inTaintTime)
@@ -245,10 +416,13 @@ public sealed class BSCharacter : BSPhysObject
245 416
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 { 418 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 419 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 420 {
250 // The next also get rid of applied linear force but the linear velocity is untouched. 421 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
251 BulletSimAPI.ClearForces2(PhysBody.ptr); 422 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
423 // The next also get rid of applied linear force but the linear velocity is untouched.
424 PhysicsScene.PE.ClearForces(PhysBody);
425 }
252 }); 426 });
253 } 427 }
254 428
@@ -263,29 +437,31 @@ public sealed class BSCharacter : BSPhysObject
263 public override OMV.Vector3 Position { 437 public override OMV.Vector3 Position {
264 get { 438 get {
265 // Don't refetch the position because this function is called a zillion times 439 // Don't refetch the position because this function is called a zillion times
266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); 440 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
267 return _position; 441 return _position;
268 } 442 }
269 set { 443 set {
270 _position = value; 444 _position = value;
271 PositionSanityCheck();
272 445
273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 446 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
274 { 447 {
275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 448 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 449 PositionSanityCheck();
450 ForcePosition = _position;
277 }); 451 });
278 } 452 }
279 } 453 }
280 public override OMV.Vector3 ForcePosition { 454 public override OMV.Vector3 ForcePosition {
281 get { 455 get {
282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 456 _position = PhysicsScene.PE.GetPosition(PhysBody);
283 return _position; 457 return _position;
284 } 458 }
285 set { 459 set {
286 _position = value; 460 _position = value;
287 PositionSanityCheck(); 461 if (PhysBody.HasPhysicalBody)
288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 462 {
463 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
464 }
289 } 465 }
290 } 466 }
291 467
@@ -297,17 +473,28 @@ public sealed class BSCharacter : BSPhysObject
297 { 473 {
298 bool ret = false; 474 bool ret = false;
299 475
476 // TODO: check for out of bounds
477 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
478 {
479 // The character is out of the known/simulated area.
480 // Force the avatar position to be within known. ScenePresence will use the position
481 // plus the velocity to decide if the avatar is moving out of the region.
482 RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
483 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
484 return true;
485 }
486
300 // If below the ground, move the avatar up 487 // If below the ground, move the avatar up
301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 488 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
302 if (Position.Z < terrainHeight) 489 if (Position.Z < terrainHeight)
303 { 490 {
304 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 491 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight);
305 _position.Z = terrainHeight + 2.0f; 492 _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters;
306 ret = true; 493 ret = true;
307 } 494 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 495 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 496 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 497 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 498 if (Position.Z < waterHeight)
312 { 499 {
313 _position.Z = waterHeight; 500 _position.Z = waterHeight;
@@ -315,7 +502,6 @@ public sealed class BSCharacter : BSPhysObject
315 } 502 }
316 } 503 }
317 504
318 // TODO: check for out of bounds
319 return ret; 505 return ret;
320 } 506 }
321 507
@@ -332,7 +518,7 @@ public sealed class BSCharacter : BSPhysObject
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 518 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 { 519 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 520 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 521 ForcePosition = _position;
336 }); 522 });
337 ret = true; 523 ret = true;
338 } 524 }
@@ -345,10 +531,10 @@ public sealed class BSCharacter : BSPhysObject
345 public override float RawMass { 531 public override float RawMass {
346 get {return _mass; } 532 get {return _mass; }
347 } 533 }
348 public override void UpdatePhysicalMassProperties(float physMass) 534 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
349 { 535 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 536 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); 537 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
352 } 538 }
353 539
354 public override OMV.Vector3 Force { 540 public override OMV.Vector3 Force {
@@ -359,7 +545,8 @@ public sealed class BSCharacter : BSPhysObject
359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 545 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
360 { 546 {
361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 547 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 548 if (PhysBody.HasPhysicalBody)
549 PhysicsScene.PE.SetObjectForce(PhysBody, _force);
363 }); 550 });
364 } 551 }
365 } 552 }
@@ -376,6 +563,37 @@ public sealed class BSCharacter : BSPhysObject
376 563
377 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 564 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
378 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 565 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
566
567 // Sets the target in the motor. This starts the changing of the avatar's velocity.
568 public override OMV.Vector3 TargetVelocity
569 {
570 get
571 {
572 return m_targetVelocity;
573 }
574 set
575 {
576 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
577 m_targetVelocity = value;
578 OMV.Vector3 targetVel = value;
579 if (_setAlwaysRun)
580 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
581
582 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
583 {
584 _velocityMotor.Reset();
585 _velocityMotor.SetTarget(targetVel);
586 _velocityMotor.SetCurrent(_velocity);
587 _velocityMotor.Enabled = true;
588 });
589 }
590 }
591 public override OMV.Vector3 RawVelocity
592 {
593 get { return _velocity; }
594 set { _velocity = value; }
595 }
596 // Directly setting velocity means this is what the user really wants now.
379 public override OMV.Vector3 Velocity { 597 public override OMV.Vector3 Velocity {
380 get { return _velocity; } 598 get { return _velocity; }
381 set { 599 set {
@@ -383,6 +601,11 @@ public sealed class BSCharacter : BSPhysObject
383 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 601 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
384 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 602 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
385 { 603 {
604 _velocityMotor.Reset();
605 _velocityMotor.SetCurrent(_velocity);
606 _velocityMotor.SetTarget(_velocity);
607 _velocityMotor.Enabled = false;
608
386 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 609 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
387 ForceVelocity = _velocity; 610 ForceVelocity = _velocity;
388 }); 611 });
@@ -391,30 +614,11 @@ public sealed class BSCharacter : BSPhysObject
391 public override OMV.Vector3 ForceVelocity { 614 public override OMV.Vector3 ForceVelocity {
392 get { return _velocity; } 615 get { return _velocity; }
393 set { 616 set {
394 // Depending on whether the avatar is moving or not, change the friction 617 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
395 // to keep the avatar from slipping around
396 if (_velocity.Length() == 0)
397 {
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
399 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
402 }
403 }
404 else
405 {
406 if (_currentFriction != PhysicsScene.Params.avatarFriction)
407 {
408 _currentFriction = PhysicsScene.Params.avatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
410 }
411 }
412 _velocity = value;
413 // Remember the set velocity so we can suppress the reduction by friction, ...
414 _appliedVelocity = value;
415 618
416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 619 _velocity = value;
417 BulletSimAPI.Activate2(PhysBody.ptr, true); 620 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
621 PhysicsScene.PE.Activate(PhysBody, true);
418 } 622 }
419 } 623 }
420 public override OMV.Vector3 Torque { 624 public override OMV.Vector3 Torque {
@@ -439,13 +643,16 @@ public sealed class BSCharacter : BSPhysObject
439 public override OMV.Quaternion Orientation { 643 public override OMV.Quaternion Orientation {
440 get { return _orientation; } 644 get { return _orientation; }
441 set { 645 set {
442 _orientation = value; 646 // 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); 647 // the viewer doesn't trust us.
444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 648 if (_orientation != value)
445 { 649 {
446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 650 _orientation = value;
447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 651 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
448 }); 652 {
653 ForceOrientation = _orientation;
654 });
655 }
449 } 656 }
450 } 657 }
451 // Go directly to Bullet to get/set the value. 658 // Go directly to Bullet to get/set the value.
@@ -453,13 +660,17 @@ public sealed class BSCharacter : BSPhysObject
453 { 660 {
454 get 661 get
455 { 662 {
456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 663 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
457 return _orientation; 664 return _orientation;
458 } 665 }
459 set 666 set
460 { 667 {
461 _orientation = value; 668 _orientation = value;
462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 669 if (PhysBody.HasPhysicalBody)
670 {
671 // _position = PhysicsScene.PE.GetPosition(BSBody);
672 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
673 }
463 } 674 }
464 } 675 }
465 public override int PhysicsActorType { 676 public override int PhysicsActorType {
@@ -478,10 +689,14 @@ public sealed class BSCharacter : BSPhysObject
478 public override bool IsStatic { 689 public override bool IsStatic {
479 get { return false; } 690 get { return false; }
480 } 691 }
692 public override bool IsPhysicallyActive {
693 get { return true; }
694 }
481 public override bool Flying { 695 public override bool Flying {
482 get { return _flying; } 696 get { return _flying; }
483 set { 697 set {
484 _flying = value; 698 _flying = value;
699
485 // simulate flying by changing the effect of gravity 700 // simulate flying by changing the effect of gravity
486 Buoyancy = ComputeBuoyancyFromFlying(_flying); 701 Buoyancy = ComputeBuoyancyFromFlying(_flying);
487 } 702 }
@@ -500,27 +715,18 @@ public sealed class BSCharacter : BSPhysObject
500 get { return _throttleUpdates; } 715 get { return _throttleUpdates; }
501 set { _throttleUpdates = value; } 716 set { _throttleUpdates = value; }
502 } 717 }
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 { 718 public override bool FloatOnWater {
516 set { 719 set {
517 _floatOnWater = value; 720 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 721 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 { 722 {
520 if (_floatOnWater) 723 if (PhysBody.HasPhysicalBody)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 724 {
522 else 725 if (_floatOnWater)
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 726 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
727 else
728 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
729 }
524 }); 730 });
525 } 731 }
526 } 732 }
@@ -549,11 +755,16 @@ public sealed class BSCharacter : BSPhysObject
549 } 755 }
550 public override float ForceBuoyancy { 756 public override float ForceBuoyancy {
551 get { return _buoyancy; } 757 get { return _buoyancy; }
552 set { _buoyancy = value; 758 set {
759 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
760
761 _buoyancy = value;
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 762 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object 763 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 764 float grav = BSParam.Gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 765 Gravity = new OMV.Vector3(0f, 0f, grav);
766 if (PhysBody.HasPhysicalBody)
767 PhysicsScene.PE.SetGravity(PhysBody, Gravity);
557 } 768 }
558 } 769 }
559 770
@@ -589,24 +800,33 @@ public sealed class BSCharacter : BSPhysObject
589 public override float APIDStrength { set { return; } } 800 public override float APIDStrength { set { return; } }
590 public override float APIDDamping { set { return; } } 801 public override float APIDDamping { set { return; } }
591 802
592 public override void AddForce(OMV.Vector3 force, bool pushforce) { 803 public override void AddForce(OMV.Vector3 force, bool pushforce)
804 {
805 // Since this force is being applied in only one step, make this a force per second.
806 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
807 AddForce(addForce, pushforce, false);
808 }
809 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
593 if (force.IsFinite()) 810 if (force.IsFinite())
594 { 811 {
595 _force.X += force.X; 812 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
596 _force.Y += force.Y; 813 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
597 _force.Z += force.Z; 814
598 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); 815 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
600 { 816 {
601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 817 // Bullet adds this central force to the total force for this tick
602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 818 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
819 if (PhysBody.HasPhysicalBody)
820 {
821 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
822 }
603 }); 823 });
604 } 824 }
605 else 825 else
606 { 826 {
607 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); 827 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
828 return;
608 } 829 }
609 //m_lastUpdateSent = false;
610 } 830 }
611 831
612 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 832 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@@ -614,24 +834,31 @@ public sealed class BSCharacter : BSPhysObject
614 public override void SetMomentum(OMV.Vector3 momentum) { 834 public override void SetMomentum(OMV.Vector3 momentum) {
615 } 835 }
616 836
617 private void ComputeAvatarScale(OMV.Vector3 size) 837 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
618 { 838 {
619 // The 'size' given by the simulator is the mid-point of the avatar 839 OMV.Vector3 newScale;
620 // and X and Y are unspecified. 840
621 841 // Bullet's capsule total height is the "passed height + radius * 2";
622 OMV.Vector3 newScale = size; 842 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 843 // The number we pass in for 'scaling' is the multiplier to get that base
624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 844 // shape to be the size desired.
625 845 // 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 846 // (size.Z) and remove the caps.
627 // The 1.15f came from ODE. Not sure what this factors in. 847 // Another oddity of the Bullet capsule implementation is that it presumes the Y
628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); 848 // dimension is the radius of the capsule. Even though some of the code allows
849 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
850
851 // Scale is multiplier of radius with one of "0.5"
852 newScale.X = size.X / 2f;
853 newScale.Y = size.Y / 2f;
629 854
630 // The total scale height is the central cylindar plus the caps on the two ends. 855 // 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); 856 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
857 // If smaller than the endcaps, just fake like we're almost that small
858 if (newScale.Z < 0)
859 newScale.Z = 0.1f;
632 860
633 // Convert diameters to radii and height to half height -- the way Bullet expects it. 861 return newScale;
634 Scale = newScale / 2f;
635 } 862 }
636 863
637 // set _avatarVolume and _mass based on capsule size, _density and Scale 864 // set _avatarVolume and _mass based on capsule size, _density and Scale
@@ -639,16 +866,16 @@ public sealed class BSCharacter : BSPhysObject
639 { 866 {
640 _avatarVolume = (float)( 867 _avatarVolume = (float)(
641 Math.PI 868 Math.PI
642 * Scale.X 869 * Size.X / 2f
643 * Scale.Y // the area of capsule cylinder 870 * Size.Y / 2f // the area of capsule cylinder
644 * Scale.Z // times height of capsule cylinder 871 * Size.Z // times height of capsule cylinder
645 + 1.33333333f 872 + 1.33333333f
646 * Math.PI 873 * Math.PI
647 * Scale.X 874 * Size.X / 2f
648 * Math.Min(Scale.X, Scale.Y) 875 * Math.Min(Size.X, Size.Y) / 2
649 * Scale.Y // plus the volume of the capsule end caps 876 * Size.Y / 2f // plus the volume of the capsule end caps
650 ); 877 );
651 _mass = _avatarDensity * _avatarVolume; 878 _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
652 } 879 }
653 880
654 // The physics engine says that properties have updated. Update same and inform 881 // The physics engine says that properties have updated. Update same and inform
@@ -657,27 +884,30 @@ public sealed class BSCharacter : BSPhysObject
657 { 884 {
658 _position = entprop.Position; 885 _position = entprop.Position;
659 _orientation = entprop.Rotation; 886 _orientation = entprop.Rotation;
660 _velocity = entprop.Velocity; 887
888 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
889 // and will send agent updates to the clients if velocity changes by more than
890 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
891 // extra updates.
892 if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f))
893 _velocity = entprop.Velocity;
894
661 _acceleration = entprop.Acceleration; 895 _acceleration = entprop.Acceleration;
662 _rotationalVelocity = entprop.RotationalVelocity; 896 _rotationalVelocity = entprop.RotationalVelocity;
897
663 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 898 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
664 PositionSanityCheck(true); 899 if (PositionSanityCheck(true))
900 {
901 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position);
902 entprop.Position = _position;
903 }
665 904
666 // remember the current and last set values 905 // remember the current and last set values
667 LastEntityProperties = CurrentEntityProperties; 906 LastEntityProperties = CurrentEntityProperties;
668 CurrentEntityProperties = entprop; 907 CurrentEntityProperties = entprop;
669 908
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 909 // Tell the linkset about value changes
680 Linkset.UpdateProperties(this); 910 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
681 911
682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 912 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
683 // base.RequestPhysicsterseUpdate(); 913 // 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..476a0e5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -39,51 +39,50 @@ 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 // 6 Dof constraint based on a midpoint between the two constrained bodies
61 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint, 62 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
64 : base(world)
64 { 65 {
65 m_world = world;
66 m_body1 = obj1; 66 m_body1 = obj1;
67 m_body2 = obj2; 67 m_body2 = obj2;
68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) 68 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 { 69 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID, 71 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 72 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}", 73 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")); 74 LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
75 m_enabled = false; 75 m_enabled = false;
76 } 76 }
77 else 77 else
78 { 78 {
79 m_constraint = new BulletConstraint( 79 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, 80 joinPoint,
82 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 81 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 82 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"), 83 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString,
85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 84 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
86 if (m_constraint.ptr == IntPtr.Zero) 85 if (!m_constraint.HasPhysicalConstraint)
87 { 86 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 87 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID); 88 LogHeader, obj1.ID, obj2.ID);
@@ -96,12 +95,27 @@ public sealed class BSConstraint6Dof : BSConstraint
96 } 95 }
97 } 96 }
98 97
98 // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object
99 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot,
100 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
101 : base(world)
102 {
103 m_body1 = obj1;
104 m_body2 = obj1; // Look out for confusion down the road
105 m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1,
106 frameInBloc, frameInBrot,
107 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
108 m_enabled = true;
109 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
110 BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString);
111 }
112
99 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 113 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
100 { 114 {
101 bool ret = false; 115 bool ret = false;
102 if (m_enabled) 116 if (m_enabled)
103 { 117 {
104 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); 118 PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
105 ret = true; 119 ret = true;
106 } 120 }
107 return ret; 121 return ret;
@@ -112,9 +126,9 @@ public sealed class BSConstraint6Dof : BSConstraint
112 bool ret = false; 126 bool ret = false;
113 if (m_enabled) 127 if (m_enabled)
114 { 128 {
115 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 129 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); 130 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); 131 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
118 ret = true; 132 ret = true;
119 } 133 }
120 return ret; 134 return ret;
@@ -125,7 +139,7 @@ public sealed class BSConstraint6Dof : BSConstraint
125 bool ret = false; 139 bool ret = false;
126 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 140 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
127 if (m_enabled) 141 if (m_enabled)
128 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); 142 ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
129 return ret; 143 return ret;
130 } 144 }
131 145
@@ -135,7 +149,7 @@ public sealed class BSConstraint6Dof : BSConstraint
135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 149 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
136 if (m_enabled) 150 if (m_enabled)
137 { 151 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); 152 ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", 153 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); 154 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 } 155 }
@@ -146,7 +160,7 @@ public sealed class BSConstraint6Dof : BSConstraint
146 { 160 {
147 bool ret = false; 161 bool ret = false;
148 if (m_enabled) 162 if (m_enabled)
149 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); 163 ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
150 return ret; 164 return ret;
151 } 165 }
152} 166}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
index a9fd826..5c8d94e 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>();
@@ -117,8 +117,7 @@ public sealed class BSConstraintCollection : IDisposable
117 if (this.TryGetConstraint(body1, body2, out constrain)) 117 if (this.TryGetConstraint(body1, body2, out constrain))
118 { 118 {
119 // remove the constraint from our collection 119 // remove the constraint from our collection
120 RemoveAndDestroyConstraint(constrain); 120 ret = RemoveAndDestroyConstraint(constrain);
121 ret = true;
122 } 121 }
123 } 122 }
124 123
@@ -126,17 +125,19 @@ public sealed class BSConstraintCollection : IDisposable
126 } 125 }
127 126
128 // The constraint MUST exist in the collection 127 // The constraint MUST exist in the collection
128 // Could be called if the constraint was previously removed.
129 // Return 'true' if the constraint was actually removed and disposed.
129 public bool RemoveAndDestroyConstraint(BSConstraint constrain) 130 public bool RemoveAndDestroyConstraint(BSConstraint constrain)
130 { 131 {
132 bool removed = false;
131 lock (m_constraints) 133 lock (m_constraints)
132 { 134 {
133 // remove the constraint from our collection 135 // remove the constraint from our collection
134 m_constraints.Remove(constrain); 136 removed = m_constraints.Remove(constrain);
135 } 137 }
136 // tell the engine that all its structures need to be freed 138 // Dispose() is safe to call multiple times
137 constrain.Dispose(); 139 constrain.Dispose();
138 // we destroyed something 140 return removed;
139 return true;
140 } 141 }
141 142
142 // Remove all constraints that reference the passed body. 143 // Remove all constraints that reference the passed body.
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..65df741 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -24,28 +24,16 @@
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; 38using OpenSim.Framework;
51using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
@@ -80,10 +68,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
80 private Quaternion m_referenceFrame = Quaternion.Identity; 68 private Quaternion m_referenceFrame = Quaternion.Identity;
81 69
82 // Linear properties 70 // Linear properties
71 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 72 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 73 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 74 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; 75 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
88 private float m_linearMotorDecayTimescale = 0; 76 private float m_linearMotorDecayTimescale = 0;
89 private float m_linearMotorTimescale = 0; 77 private float m_linearMotorTimescale = 0;
@@ -93,16 +81,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
93 // private Vector3 m_linearMotorOffset = Vector3.Zero; 81 // private Vector3 m_linearMotorOffset = Vector3.Zero;
94 82
95 //Angular properties 83 //Angular properties
84 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 85 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
97 // private int m_angularMotorApply = 0; // application frame counter 86 // private int m_angularMotorApply = 0; // application frame counter
98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 87 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
99 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 88 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
100 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 89 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
101 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 90 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
102 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body 91 private Vector3 m_lastAngularVelocity = Vector3.Zero;
103 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 92 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
104 93
105 //Deflection properties 94 //Deflection properties
95 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
106 private float m_angularDeflectionEfficiency = 0; 96 private float m_angularDeflectionEfficiency = 0;
107 private float m_angularDeflectionTimescale = 0; 97 private float m_angularDeflectionTimescale = 0;
108 private float m_linearDeflectionEfficiency = 0; 98 private float m_linearDeflectionEfficiency = 0;
@@ -114,33 +104,68 @@ namespace OpenSim.Region.Physics.BulletSPlugin
114 private float m_bankingTimescale = 0; 104 private float m_bankingTimescale = 0;
115 105
116 //Hover and Buoyancy properties 106 //Hover and Buoyancy properties
107 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
117 private float m_VhoverHeight = 0f; 108 private float m_VhoverHeight = 0f;
118 private float m_VhoverEfficiency = 0f; 109 private float m_VhoverEfficiency = 0f;
119 private float m_VhoverTimescale = 0f; 110 private float m_VhoverTimescale = 0f;
120 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 111 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
121 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. 112 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
122 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) 113 private float m_VehicleBuoyancy = 0f;
123 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. 114 private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set
124 // 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;
126
127 // For debugging, flags to turn on and off individual corrections.
128 public bool enableAngularVerticalAttraction;
129 public bool enableAngularDeflection;
130 public bool enableAngularBanking;
129 131
130 public BSDynamics(BSScene myScene, BSPrim myPrim) 132 public BSDynamics(BSScene myScene, BSPrim myPrim)
131 { 133 {
132 PhysicsScene = myScene; 134 PhysicsScene = myScene;
133 Prim = myPrim; 135 Prim = myPrim;
134 Type = Vehicle.TYPE_NONE; 136 Type = Vehicle.TYPE_NONE;
137 SetupVehicleDebugging();
138 }
139
140 // Stopgap debugging enablement. Allows source level debugging but still checking
141 // in changes by making enablement of debugging flags from INI file.
142 public void SetupVehicleDebugging()
143 {
144 enableAngularVerticalAttraction = true;
145 enableAngularDeflection = false;
146 enableAngularBanking = true;
147 if (BSParam.VehicleDebuggingEnabled)
148 {
149 enableAngularVerticalAttraction = true;
150 enableAngularDeflection = false;
151 enableAngularBanking = false;
152 }
135 } 153 }
136 154
137 // Return 'true' if this vehicle is doing vehicle things 155 // Return 'true' if this vehicle is doing vehicle things
138 public bool IsActive 156 public bool IsActive
139 { 157 {
140 get { return Type != Vehicle.TYPE_NONE; } 158 get { return (Type != Vehicle.TYPE_NONE && Prim.IsPhysicallyActive); }
141 } 159 }
142 160
143 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 161 // Return 'true' if this a vehicle that should be sitting on the ground
162 public bool IsGroundVehicle
163 {
164 get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); }
165 }
166
167 #region Vehicle parameter setting
168 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
144 { 169 {
145 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 170 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
146 switch (pParam) 171 switch (pParam)
@@ -152,13 +177,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 177 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
153 break; 178 break;
154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 179 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 180 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
181 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
156 break; 182 break;
157 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 183 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
158 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 184 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
185 m_angularMotor.TimeScale = m_angularMotorTimescale;
159 break; 186 break;
160 case Vehicle.BANKING_EFFICIENCY: 187 case Vehicle.BANKING_EFFICIENCY:
161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 188 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
162 break; 189 break;
163 case Vehicle.BANKING_MIX: 190 case Vehicle.BANKING_MIX:
164 m_bankingMix = Math.Max(pValue, 0.01f); 191 m_bankingMix = Math.Max(pValue, 0.01f);
@@ -167,10 +194,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
167 m_bankingTimescale = Math.Max(pValue, 0.01f); 194 m_bankingTimescale = Math.Max(pValue, 0.01f);
168 break; 195 break;
169 case Vehicle.BUOYANCY: 196 case Vehicle.BUOYANCY:
170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 197 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
198 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy);
171 break; 199 break;
172 case Vehicle.HOVER_EFFICIENCY: 200 case Vehicle.HOVER_EFFICIENCY:
173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 201 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
174 break; 202 break;
175 case Vehicle.HOVER_HEIGHT: 203 case Vehicle.HOVER_HEIGHT:
176 m_VhoverHeight = pValue; 204 m_VhoverHeight = pValue;
@@ -185,33 +213,41 @@ namespace OpenSim.Region.Physics.BulletSPlugin
185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 213 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
186 break; 214 break;
187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 215 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 216 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
217 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 218 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 219 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 220 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
221 m_linearMotor.TimeScale = m_linearMotorTimescale;
192 break; 222 break;
193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 223 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 224 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
225 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
195 break; 226 break;
196 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 227 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
197 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 228 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
229 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
198 break; 230 break;
199 231
200 // These are vector properties but the engine lets you use a single float value to 232 // 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 233 // set all of the components to the same value
202 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 234 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
203 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 235 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
204 break; 237 break;
205 case Vehicle.ANGULAR_MOTOR_DIRECTION: 238 case Vehicle.ANGULAR_MOTOR_DIRECTION:
206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 239 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
207 // m_angularMotorApply = 100; 240 m_angularMotor.Zero();
241 m_angularMotor.SetTarget(m_angularMotorDirection);
208 break; 242 break;
209 case Vehicle.LINEAR_FRICTION_TIMESCALE: 243 case Vehicle.LINEAR_FRICTION_TIMESCALE:
210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 244 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
245 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
211 break; 246 break;
212 case Vehicle.LINEAR_MOTOR_DIRECTION: 247 case Vehicle.LINEAR_MOTOR_DIRECTION:
213 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 248 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 249 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
250 m_linearMotor.SetTarget(m_linearMotorDirection);
215 break; 251 break;
216 case Vehicle.LINEAR_MOTOR_OFFSET: 252 case Vehicle.LINEAR_MOTOR_OFFSET:
217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 253 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,21 +263,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
227 { 263 {
228 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 264 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 265 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
266 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
230 break; 267 break;
231 case Vehicle.ANGULAR_MOTOR_DIRECTION: 268 case Vehicle.ANGULAR_MOTOR_DIRECTION:
232 // Limit requested angular speed to 2 rps= 4 pi rads/sec 269 // Limit requested angular speed to 2 rps= 4 pi rads/sec
233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); 270 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 271 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 272 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 273 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
237 // m_angularMotorApply = 100; 274 m_angularMotor.Zero();
275 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break; 276 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE: 277 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 278 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
279 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
241 break; 280 break;
242 case Vehicle.LINEAR_MOTOR_DIRECTION: 281 case Vehicle.LINEAR_MOTOR_DIRECTION:
243 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 282 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 283 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
284 m_linearMotor.SetTarget(m_linearMotorDirection);
245 break; 285 break;
246 case Vehicle.LINEAR_MOTOR_OFFSET: 286 case Vehicle.LINEAR_MOTOR_OFFSET:
247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 287 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -281,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
281 } 321 }
282 } 322 }
283 323
284 internal void ProcessTypeChange(Vehicle pType) 324 public void ProcessTypeChange(Vehicle pType)
285 { 325 {
286 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); 326 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
287 // Set Defaults For Type 327 // Set Defaults For Type
@@ -303,7 +343,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
303 m_VhoverEfficiency = 0; 343 m_VhoverEfficiency = 0;
304 m_VhoverTimescale = 0; 344 m_VhoverTimescale = 0;
305 m_VehicleBuoyancy = 0; 345 m_VehicleBuoyancy = 0;
306 346
307 m_linearDeflectionEfficiency = 1; 347 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1; 348 m_linearDeflectionTimescale = 1;
309 349
@@ -319,6 +359,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
319 359
320 m_referenceFrame = Quaternion.Identity; 360 m_referenceFrame = Quaternion.Identity;
321 m_flags = (VehicleFlag)0; 361 m_flags = (VehicleFlag)0;
362
322 break; 363 break;
323 364
324 case Vehicle.TYPE_SLED: 365 case Vehicle.TYPE_SLED:
@@ -351,10 +392,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
351 m_bankingMix = 1; 392 m_bankingMix = 1;
352 393
353 m_referenceFrame = Quaternion.Identity; 394 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 395 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
355 m_flags &= 396 | VehicleFlag.HOVER_TERRAIN_ONLY
356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 397 | VehicleFlag.HOVER_GLOBAL_HEIGHT
357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 398 | VehicleFlag.HOVER_UP_ONLY);
399 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
400 | VehicleFlag.LIMIT_ROLL_ONLY
401 | VehicleFlag.LIMIT_MOTOR_UP);
402
358 break; 403 break;
359 case Vehicle.TYPE_CAR: 404 case Vehicle.TYPE_CAR:
360 m_linearMotorDirection = Vector3.Zero; 405 m_linearMotorDirection = Vector3.Zero;
@@ -498,6 +543,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
498 m_bankingEfficiency = 0; 543 m_bankingEfficiency = 0;
499 m_bankingMix = 0.7f; 544 m_bankingMix = 0.7f;
500 m_bankingTimescale = 5; 545 m_bankingTimescale = 5;
546
501 m_referenceFrame = Quaternion.Identity; 547 m_referenceFrame = Quaternion.Identity;
502 548
503 m_referenceFrame = Quaternion.Identity; 549 m_referenceFrame = Quaternion.Identity;
@@ -510,152 +556,467 @@ namespace OpenSim.Region.Physics.BulletSPlugin
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 556 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
511 break; 557 break;
512 } 558 }
559
560 // Update any physical parameters based on this type.
561 Refresh();
562
563 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
564 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
565 1f);
566 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
567
568 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
569 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
570 1f);
571 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
572
573 /* Not implemented
574 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
575 BSMotor.Infinite, BSMotor.InfiniteVector,
576 m_verticalAttractionEfficiency);
577 // Z goes away and we keep X and Y
578 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
579 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
580 */
581 }
582 #endregion // Vehicle parameter setting
583
584 public void Refresh()
585 {
586 // If asking for a refresh, reset the physical parameters before the next simulation step.
587 PhysicsScene.PostTaintObject("BSDynamics.Refresh", Prim.LocalID, delegate()
588 {
589 SetPhysicalParameters();
590 });
513 } 591 }
514 592
515 // Some of the properties of this prim may have changed. 593 // Some of the properties of this prim may have changed.
516 // Do any updating needed for a vehicle 594 // Do any updating needed for a vehicle
517 public void Refresh() 595 private void SetPhysicalParameters()
518 { 596 {
519 if (IsActive) 597 if (IsActive)
520 { 598 {
521 // Friction effects are handled by this vehicle code 599 // Remember the mass so we don't have to fetch it every step
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); 600 m_vehicleMass = Prim.TotalMass;
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); 601
524 602 // Friction affects are handled by this vehicle code
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); 603 PhysicsScene.PE.SetFriction(Prim.PhysBody, BSParam.VehicleFriction);
526 604 PhysicsScene.PE.SetRestitution(Prim.PhysBody, BSParam.VehicleRestitution);
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); 605
606 // Moderate angular movement introduced by Bullet.
607 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
608 // Maybe compute linear and angular factor and damping from params.
609 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, BSParam.VehicleAngularDamping);
610 PhysicsScene.PE.SetLinearFactor(Prim.PhysBody, BSParam.VehicleLinearFactor);
611 PhysicsScene.PE.SetAngularFactorV(Prim.PhysBody, BSParam.VehicleAngularFactor);
612
613 // Vehicles report collision events so we know when it's on the ground
614 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
615
616 Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass);
617 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia);
618 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody);
619
620 // Set the gravity for the vehicle depending on the buoyancy
621 // TODO: what should be done if prim and vehicle buoyancy differ?
622 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy);
623 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
624 PhysicsScene.PE.SetGravity(Prim.PhysBody, Vector3.Zero);
625
626 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
627 Prim.LocalID, m_vehicleMass, Prim.Inertia, m_VehicleGravity,
628 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
629 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
630 );
631 }
632 else
633 {
634 if (Prim.PhysBody.HasPhysicalBody)
635 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
528 } 636 }
529 } 637 }
530 638
531 public bool RemoveBodyDependencies(BSPhysObject prim) 639 public bool RemoveBodyDependencies(BSPhysObject prim)
532 { 640 {
533 // If active, we need to add our properties back when the body is rebuilt. 641 Refresh();
534 return IsActive; 642 return IsActive;
535 } 643 }
536 644
537 public void RestoreBodyDependencies(BSPhysObject prim) 645 #region Known vehicle value functions
646 // Vehicle physical parameters that we buffer from constant getting and setting.
647 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
648 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
649 // This does two things: 1) saves continuious calls into unmanaged code, and
650 // 2) signals when a physics property update must happen back to the simulator
651 // to update values modified for the vehicle.
652 private int m_knownChanged;
653 private int m_knownHas;
654 private float m_knownTerrainHeight;
655 private float m_knownWaterLevel;
656 private Vector3 m_knownPosition;
657 private Vector3 m_knownVelocity;
658 private Vector3 m_knownForce;
659 private Vector3 m_knownForceImpulse;
660 private Quaternion m_knownOrientation;
661 private Vector3 m_knownRotationalVelocity;
662 private Vector3 m_knownRotationalForce;
663 private Vector3 m_knownRotationalImpulse;
664 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
665
666 private const int m_knownChangedPosition = 1 << 0;
667 private const int m_knownChangedVelocity = 1 << 1;
668 private const int m_knownChangedForce = 1 << 2;
669 private const int m_knownChangedForceImpulse = 1 << 3;
670 private const int m_knownChangedOrientation = 1 << 4;
671 private const int m_knownChangedRotationalVelocity = 1 << 5;
672 private const int m_knownChangedRotationalForce = 1 << 6;
673 private const int m_knownChangedRotationalImpulse = 1 << 7;
674 private const int m_knownChangedTerrainHeight = 1 << 8;
675 private const int m_knownChangedWaterLevel = 1 << 9;
676 private const int m_knownChangedForwardVelocity = 1 <<10;
677
678 public void ForgetKnownVehicleProperties()
679 {
680 m_knownHas = 0;
681 m_knownChanged = 0;
682 }
683 // Push all the changed values back into the physics engine
684 public void PushKnownChanged()
685 {
686 if (m_knownChanged != 0)
687 {
688 if ((m_knownChanged & m_knownChangedPosition) != 0)
689 Prim.ForcePosition = m_knownPosition;
690
691 if ((m_knownChanged & m_knownChangedOrientation) != 0)
692 Prim.ForceOrientation = m_knownOrientation;
693
694 if ((m_knownChanged & m_knownChangedVelocity) != 0)
695 {
696 Prim.ForceVelocity = m_knownVelocity;
697 // Fake out Bullet by making it think the velocity is the same as last time.
698 // Bullet does a bunch of smoothing for changing parameters.
699 // Since the vehicle is demanding this setting, we override Bullet's smoothing
700 // by telling Bullet the value was the same last time.
701 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
702 }
703
704 if ((m_knownChanged & m_knownChangedForce) != 0)
705 Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
706
707 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
708 Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
709
710 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
711 {
712 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
713 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
714 }
715
716 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
717 Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
718
719 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
720 {
721 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
722 }
723
724 // If we set one of the values (ie, the physics engine didn't do it) we must force
725 // an UpdateProperties event to send the changes up to the simulator.
726 PhysicsScene.PE.PushUpdate(Prim.PhysBody);
727 }
728 m_knownChanged = 0;
729 }
730
731 // Since the computation of terrain height can be a little involved, this routine
732 // is used to fetch the height only once for each vehicle simulation step.
733 Vector3 lastRememberedHeightPos;
734 private float GetTerrainHeight(Vector3 pos)
538 { 735 {
539 if (Prim.LocalID != prim.LocalID) 736 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
540 { 737 {
541 // The call should be on us by our prim. Error if not. 738 lastRememberedHeightPos = pos;
542 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}", 739 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
543 LogHeader, prim.LocalID, Prim.LocalID); 740 m_knownHas |= m_knownChangedTerrainHeight;
544 return; 741 }
742 return m_knownTerrainHeight;
743 }
744
745 // Since the computation of water level can be a little involved, this routine
746 // is used ot fetch the level only once for each vehicle simulation step.
747 private float GetWaterLevel(Vector3 pos)
748 {
749 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
750 {
751 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
752 m_knownHas |= m_knownChangedWaterLevel;
753 }
754 return (float)m_knownWaterLevel;
755 }
756
757 private Vector3 VehiclePosition
758 {
759 get
760 {
761 if ((m_knownHas & m_knownChangedPosition) == 0)
762 {
763 m_knownPosition = Prim.ForcePosition;
764 m_knownHas |= m_knownChangedPosition;
765 }
766 return m_knownPosition;
767 }
768 set
769 {
770 m_knownPosition = value;
771 m_knownChanged |= m_knownChangedPosition;
772 m_knownHas |= m_knownChangedPosition;
545 } 773 }
546 Refresh();
547 } 774 }
548 775
776 private Quaternion VehicleOrientation
777 {
778 get
779 {
780 if ((m_knownHas & m_knownChangedOrientation) == 0)
781 {
782 m_knownOrientation = Prim.ForceOrientation;
783 m_knownHas |= m_knownChangedOrientation;
784 }
785 return m_knownOrientation;
786 }
787 set
788 {
789 m_knownOrientation = value;
790 m_knownChanged |= m_knownChangedOrientation;
791 m_knownHas |= m_knownChangedOrientation;
792 }
793 }
794
795 private Vector3 VehicleVelocity
796 {
797 get
798 {
799 if ((m_knownHas & m_knownChangedVelocity) == 0)
800 {
801 m_knownVelocity = Prim.ForceVelocity;
802 m_knownHas |= m_knownChangedVelocity;
803 }
804 return m_knownVelocity;
805 }
806 set
807 {
808 m_knownVelocity = value;
809 m_knownChanged |= m_knownChangedVelocity;
810 m_knownHas |= m_knownChangedVelocity;
811 }
812 }
813
814 private void VehicleAddForce(Vector3 pForce)
815 {
816 if ((m_knownHas & m_knownChangedForce) == 0)
817 {
818 m_knownForce = Vector3.Zero;
819 m_knownHas |= m_knownChangedForce;
820 }
821 m_knownForce += pForce;
822 m_knownChanged |= m_knownChangedForce;
823 }
824
825 private void VehicleAddForceImpulse(Vector3 pImpulse)
826 {
827 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
828 {
829 m_knownForceImpulse = Vector3.Zero;
830 m_knownHas |= m_knownChangedForceImpulse;
831 }
832 m_knownForceImpulse += pImpulse;
833 m_knownChanged |= m_knownChangedForceImpulse;
834 }
835
836 private Vector3 VehicleRotationalVelocity
837 {
838 get
839 {
840 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
841 {
842 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
843 m_knownHas |= m_knownChangedRotationalVelocity;
844 }
845 return (Vector3)m_knownRotationalVelocity;
846 }
847 set
848 {
849 m_knownRotationalVelocity = value;
850 m_knownChanged |= m_knownChangedRotationalVelocity;
851 m_knownHas |= m_knownChangedRotationalVelocity;
852 }
853 }
854 private void VehicleAddAngularForce(Vector3 aForce)
855 {
856 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
857 {
858 m_knownRotationalForce = Vector3.Zero;
859 }
860 m_knownRotationalForce += aForce;
861 m_knownChanged |= m_knownChangedRotationalForce;
862 m_knownHas |= m_knownChangedRotationalForce;
863 }
864 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
865 {
866 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
867 {
868 m_knownRotationalImpulse = Vector3.Zero;
869 m_knownHas |= m_knownChangedRotationalImpulse;
870 }
871 m_knownRotationalImpulse += pImpulse;
872 m_knownChanged |= m_knownChangedRotationalImpulse;
873 }
874
875 // Vehicle relative forward velocity
876 private Vector3 VehicleForwardVelocity
877 {
878 get
879 {
880 if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
881 {
882 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
883 m_knownHas |= m_knownChangedForwardVelocity;
884 }
885 return m_knownForwardVelocity;
886 }
887 }
888 private float VehicleForwardSpeed
889 {
890 get
891 {
892 return VehicleForwardVelocity.X;
893 }
894 }
895
896 #endregion // Known vehicle value functions
897
549 // One step of the vehicle properties for the next 'pTimestep' seconds. 898 // One step of the vehicle properties for the next 'pTimestep' seconds.
550 internal void Step(float pTimestep) 899 internal void Step(float pTimestep)
551 { 900 {
552 if (!IsActive) return; 901 if (!IsActive) return;
553 902
554 // DEBUG 903 ForgetKnownVehicleProperties();
555 // Because Bullet does apply forces to the vehicle, our last computed
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
563 m_vehicleMass = Prim.Linkset.LinksetMass;
564 904
565 MoveLinear(pTimestep); 905 MoveLinear(pTimestep);
566 // Commented out for debug
567 MoveAngular(pTimestep); 906 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570 907
571 LimitRotation(pTimestep); 908 LimitRotation(pTimestep);
572 909
573 // remember the position so next step we can limit absolute movement effects 910 // remember the position so next step we can limit absolute movement effects
574 m_lastPositionVector = Prim.ForcePosition; 911 m_lastPositionVector = VehiclePosition;
575 912
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG 913 // If we forced the changing of some vehicle parameters, update the values and
577 Prim.LocalID, 914 // for the physics engine to note the changes so an UpdateProperties event will happen.
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), 915 PushKnownChanged();
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), 916
580 Prim.Inertia, 917 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
581 m_vehicleMass 918 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
582 ); 919
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 920 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 921 Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
585 }// end Step 922 }
586 923
587 // Apply the effect of the linear motor. 924 // Called after the simulation step
588 // Also does hover and float. 925 internal void PostStep(float pTimestep)
926 {
927 if (!IsActive) return;
928
929 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
930 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
931 }
932
933 // Apply the effect of the linear motor and other linear motions (like hover and float).
589 private void MoveLinear(float pTimestep) 934 private void MoveLinear(float pTimestep)
590 { 935 {
591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates 936 ComputeLinearVelocity(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 937
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete 938 ComputeLinearTerrainHeightCorrection(pTimestep);
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
602 m_lastLinearVelocityVector += addAmount;
603 939
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; 940 ComputeLinearHover(pTimestep);
605 m_linearMotorDirection *= (1f - decayFactor);
606 941
607 // Rotate new object velocity from vehicle relative to world coordinates 942 ComputeLinearBlockingEndPoint(pTimestep);
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
609 943
610 // Apply friction for next time 944 ComputeLinearMotorUp(pTimestep);
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
613 945
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", 946 ApplyGravity(pTimestep);
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, 947
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); 948 // If not changing some axis, reduce out velocity
617 } 949 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
618 else
619 { 950 {
620 // if what remains of direction is very small, zero it. 951 Vector3 vel = VehicleVelocity;
621 m_linearMotorDirection = Vector3.Zero; 952 if ((m_flags & (VehicleFlag.NO_X)) != 0)
622 m_lastLinearVelocityVector = Vector3.Zero; 953 vel.X = 0;
623 m_newVelocity = Vector3.Zero; 954 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
955 vel.Y = 0;
956 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
957 vel.Z = 0;
958 VehicleVelocity = vel;
959 }
624 960
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 961 // ==================================================================
962 // Clamp high or low velocities
963 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
964 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared)
965 {
966 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
967 VehicleVelocity /= VehicleVelocity.Length();
968 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
969 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
970 Prim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
626 } 971 }
972 else if (newVelocityLengthSq < 0.001f)
973 VehicleVelocity = Vector3.Zero;
627 974
628 // m_newVelocity is velocity computed from linear motor in world coordinates 975 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity );
629 976
630 // Gravity and Buoyancy 977 } // end MoveLinear()
631 // There is some gravity, make a gravity force vector that is applied after object velocity.
632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
634 978
635 /* 979 public void ComputeLinearVelocity(float pTimestep)
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... 980 {
637 // Preserve the current Z velocity 981 // Step the motor from the current value. Get the correction needed this step.
638 Vector3 vel_now = m_prim.Velocity; 982 Vector3 origVelW = VehicleVelocity; // DEBUG
639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 983 Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation);
640 */ 984 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
985
986 // Motor is vehicle coordinates. Rotate it to world coordinates
987 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation;
988
989 // If we're a ground vehicle, don't add any upward Z movement
990 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
991 {
992 if (linearMotorVelocityW.Z > 0f)
993 linearMotorVelocityW.Z = 0f;
994 }
995
996 // Add this correction to the velocity to make it faster/slower.
997 VehicleVelocity += linearMotorVelocityW;
641 998
642 Vector3 pos = Prim.ForcePosition; 999 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5}",
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); 1000 Prim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity);
1001 }
644 1002
1003 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
1004 {
645 // If below the terrain, move us above the ground a little. 1005 // If below the terrain, move us above the ground a little.
646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 1006 // 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. 1007 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 { 1008 {
653 pos.Z = terrainHeight + 2; 1009 // Force position because applying force won't get the vehicle through the terrain
654 Prim.ForcePosition = pos; 1010 Vector3 newPosition = VehiclePosition;
655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 1011 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
1012 VehiclePosition = newPosition;
1013 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
1014 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
656 } 1015 }
1016 }
657 1017
658 // Check if hovering 1018 public void ComputeLinearHover(float pTimestep)
1019 {
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 1020 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height 1021 // m_VhoverTimescale: time to achieve height
661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 1022 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -663,11 +1024,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
663 // We should hover, get the target height 1024 // We should hover, get the target height
664 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 1025 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
665 { 1026 {
666 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 1027 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
667 } 1028 }
668 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 1029 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
669 { 1030 {
670 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; 1031 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
671 } 1032 }
672 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 1033 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
673 { 1034 {
@@ -677,45 +1038,63 @@ namespace OpenSim.Region.Physics.BulletSPlugin
677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 1038 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
678 { 1039 {
679 // If body is already heigher, use its height as target height 1040 // If body is already heigher, use its height as target height
680 if (pos.Z > m_VhoverTargetHeight) 1041 if (VehiclePosition.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z; 1042 m_VhoverTargetHeight = VehiclePosition.Z;
682 } 1043 }
1044
683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1045 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
684 { 1046 {
685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 1047 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
686 { 1048 {
1049 Vector3 pos = VehiclePosition;
687 pos.Z = m_VhoverTargetHeight; 1050 pos.Z = m_VhoverTargetHeight;
688 Prim.ForcePosition = pos; 1051 VehiclePosition = pos;
1052
1053 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos);
689 } 1054 }
690 } 1055 }
691 else 1056 else
692 { 1057 {
693 float verticalError = pos.Z - m_VhoverTargetHeight; 1058 // Error is positive if below the target and negative if above.
694 // RA: where does the 50 come from? 1059 Vector3 hpos = VehiclePosition;
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 1060 float verticalError = m_VhoverTargetHeight - hpos.Z;
696 // Replace Vertical speed with correction figure if significant 1061 float verticalCorrection = verticalError / m_VhoverTimescale;
697 if (Math.Abs(verticalError) > 0.01f) 1062 verticalCorrection *= m_VhoverEfficiency;
698 { 1063
699 m_newVelocity.Z += verticalCorrectionVelocity; 1064 hpos.Z += verticalCorrection;
700 //KF: m_VhoverEfficiency is not yet implemented 1065 VehiclePosition = hpos;
701 } 1066
702 else if (verticalError < -0.01) 1067 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
703 { 1068 Vector3 vel = VehicleVelocity;
704 m_newVelocity.Z -= verticalCorrectionVelocity; 1069 vel.Z = 0f;
705 } 1070 VehicleVelocity = vel;
706 else 1071
707 { 1072 /*
708 m_newVelocity.Z = 0f; 1073 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
709 } 1074 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1075 verticalCorrection *= m_vehicleMass;
1076
1077 // TODO: implement m_VhoverEfficiency correctly
1078 VehicleAddForceImpulse(verticalCorrection);
1079 */
1080
1081 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
1082 Prim.LocalID, VehiclePosition, m_VhoverEfficiency,
1083 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1084 verticalError, verticalCorrection);
710 } 1085 }
711 1086
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
713 } 1087 }
1088 }
714 1089
1090 public bool ComputeLinearBlockingEndPoint(float pTimestep)
1091 {
1092 bool changed = false;
1093
1094 Vector3 pos = VehiclePosition;
715 Vector3 posChange = pos - m_lastPositionVector; 1095 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 1096 if (m_BlockingEndPoint != Vector3.Zero)
717 { 1097 {
718 bool changed = false;
719 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 1098 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
720 { 1099 {
721 pos.X -= posChange.X + 1; 1100 pos.X -= posChange.X + 1;
@@ -743,233 +1122,119 @@ namespace OpenSim.Region.Physics.BulletSPlugin
743 } 1122 }
744 if (changed) 1123 if (changed)
745 { 1124 {
746 Prim.ForcePosition = pos; 1125 VehiclePosition = pos;
747 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1126 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1127 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
749 } 1128 }
750 } 1129 }
1130 return changed;
1131 }
751 1132
752 #region downForce 1133 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
753 Vector3 downForce = Vector3.Zero; 1134 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
754 1135 // used with conjunction with banking: the strength of the banking will decay when the
1136 // vehicle no longer experiences collisions. The decay timescale is the same as
1137 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1138 // when they are in mid jump.
1139 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1140 // This is just using the ground and a general collision check. Should really be using
1141 // a downward raycast to find what is below.
1142 public void ComputeLinearMotorUp(float pTimestep)
1143 {
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1144 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 1145 {
757 // If the vehicle is motoring into the sky, get it going back down. 1146 // This code tries to decide if the object is not on the ground and then pushing down
758 // Is this an angular force or both linear and angular?? 1147 /*
759 float distanceAboveGround = pos.Z - terrainHeight; 1148 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
760 if (distanceAboveGround > 2f) 1149 distanceAboveGround = VehiclePosition.Z - targetHeight;
1150 // Not colliding if the vehicle is off the ground
1151 if (!Prim.IsColliding)
761 { 1152 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1153 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 1154 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
765 } 1155 }
766 // TODO: this calculation is all wrong. From the description at 1156 // TODO: this calculation is wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1157 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 1158 // has a decay factor. This says this force should
769 // be computed with a motor. 1159 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 1160 // TODO: add interaction with banking.
771 Prim.LocalID, distanceAboveGround, downForce); 1161 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
772 } 1162 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
773 #endregion // downForce 1163 */
774 1164
775 // If not changing some axis, reduce out velocity 1165 // Another approach is to measure if we're going up. If going up and not colliding,
776 if ((m_flags & (VehicleFlag.NO_X)) != 0) 1166 // the vehicle is in the air. Fix that by pushing down.
777 m_newVelocity.X = 0; 1167 if (!Prim.IsColliding && VehicleVelocity.Z > 0.1)
778 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 1168 {
779 m_newVelocity.Y = 0; 1169 // Get rid of any of the velocity vector that is pushing us up.
780 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 1170 float upVelocity = VehicleVelocity.Z;
781 m_newVelocity.Z = 0; 1171 VehicleVelocity += new Vector3(0, 0, -upVelocity);
782 1172
783 // Clamp REALLY high or low velocities 1173 /*
784 if (m_newVelocity.LengthSquared() > 1e6f) 1174 // If we're pointed up into the air, we should nose down
785 { 1175 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
786 m_newVelocity /= m_newVelocity.Length(); 1176 // The rotation around the Y axis is pitch up or down
787 m_newVelocity *= 1000f; 1177 if (pointingDirection.Y > 0.01f)
1178 {
1179 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
1180 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
1181 // Rotate into world coordinates and apply to vehicle
1182 angularCorrectionVector *= VehicleOrientation;
1183 VehicleAddAngularForce(angularCorrectionVector);
1184 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
1185 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
1186 }
1187 */
1188 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1189 Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity);
1190 }
788 } 1191 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f) 1192 }
790 m_newVelocity = Vector3.Zero;
791 1193
792 // Stuff new linear velocity into the vehicle 1194 private void ApplyGravity(float pTimeStep)
793 Prim.ForceVelocity = m_newVelocity; 1195 {
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG 1196 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
795 1197
796 Vector3 totalDownForce = downForce + grav; 1198 // Hack to reduce downward force if the vehicle is probably sitting on the ground
797 if (totalDownForce != Vector3.Zero) 1199 if (Prim.IsColliding && IsGroundVehicle)
798 { 1200 appliedGravity *= BSParam.VehicleGroundGravityFudge;
799 Prim.AddForce(totalDownForce * m_vehicleMass, false);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
801 }
802 1201
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", 1202 VehicleAddForce(appliedGravity);
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
805 1203
806 } // end MoveLinear() 1204 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}",
1205 Prim.LocalID, m_VehicleGravity,
1206 Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1207 }
807 1208
808 // ======================================================================= 1209 // =======================================================================
1210 // =======================================================================
809 // Apply the effect of the angular motor. 1211 // Apply the effect of the angular motor.
1212 // The 'contribution' is how much angular correction velocity each function wants.
1213 // All the contributions are added together and the resulting velocity is
1214 // set directly on the vehicle.
810 private void MoveAngular(float pTimestep) 1215 private void MoveAngular(float pTimestep)
811 { 1216 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 1217 ComputeAngularTurning(pTimestep);
813 // m_angularMotorApply // application frame counter
814 // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
815 // m_angularMotorTimescale // motor angular velocity ramp up rate
816 // m_angularMotorDecayTimescale // motor angular velocity decay rate
817 // m_angularFrictionTimescale // body angular velocity decay rate
818 // m_lastAngularVelocity // what was last applied to body
819
820 if (m_angularMotorDirection.LengthSquared() > 0.0001)
821 {
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 1218
831 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", 1219 ComputeAngularVerticalAttraction();
832 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
833 }
834 else
835 {
836 m_angularMotorVelocity = Vector3.Zero;
837 }
838 1220
839 #region Vertical attactor 1221 ComputeAngularDeflection();
840 1222
841 Vector3 vertattr = Vector3.Zero; 1223 ComputeAngularBanking();
842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844 1224
845 // If vertical attaction timescale is reasonable and we applied an angular force last time... 1225 // ==================================================================
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 1226 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f))
847 { 1227 {
848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; 1228 // The vehicle is not adding anything angular wise.
849 if (Prim.IsColliding) 1229 VehicleRotationalVelocity = Vector3.Zero;
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); 1230 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
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
878 // scaling appears better usingsquare-law
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
884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
886
887 }
888 #endregion // Vertical attactor
889
890 #region Deflection
891
892 if (m_angularDeflectionEfficiency != 0)
893 {
894 // Compute a scaled vector that points in the preferred axis (X direction)
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 } 1231 }
909 1232 else
910 #endregion
911
912 #region Banking
913
914 if (m_bankingEfficiency != 0)
915 { 1233 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1234 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", Prim.LocalID, VehicleRotationalVelocity);
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
918 //Changes which way it banks in and out of turns
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 } 1235 }
963 1236
964 #endregion 1237 // ==================================================================
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 1238 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero) 1239 if (m_linearMotorOffset != Vector3.Zero)
975 { 1240 {
@@ -985,8 +1250,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
985 // 1250 //
986 // The torque created is the linear velocity crossed with the offset 1251 // The torque created is the linear velocity crossed with the offset
987 1252
988 // NOTE: this computation does should be in the linear section 1253 // TODO: this computation should be in the linear section
989 // because there we know the impulse being applied. 1254 // because that is where we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero; 1255 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); 1256 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X)) 1257 if (float.IsNaN(torqueFromOffset.X))
@@ -995,47 +1260,258 @@ namespace OpenSim.Region.Physics.BulletSPlugin
995 torqueFromOffset.Y = 0; 1260 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z)) 1261 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0; 1262 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass; 1263
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true); 1264 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1265 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 } 1266 }
1002 1267
1003 #endregion 1268 }
1269
1270 private void ComputeAngularTurning(float pTimestep)
1271 {
1272 // The user wants this many radians per second angular change?
1273 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation);
1274 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1275
1276 // ==================================================================
1277 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1278 // This flag prevents linear deflection parallel to world z-axis. This is useful
1279 // for preventing ground vehicles with large linear deflection, like bumper cars,
1280 // from climbing their linear deflection into the sky.
1281 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1282 // TODO: This is here because this is where ODE put it but documentation says it
1283 // is a linear effect. Where should this check go?
1284 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1285 // {
1286 // angularMotorContributionV.X = 0f;
1287 // angularMotorContributionV.Y = 0f;
1288 // }
1289
1290 VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
1291 VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
1292 }
1293
1294 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1295 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1296 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1297 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1298 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1299 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1300 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1301 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1302 public void ComputeAngularVerticalAttraction()
1303 {
1004 1304
1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1305 // If vertical attaction timescale is reasonable
1306 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1006 { 1307 {
1007 m_lastAngularVelocity.X = 0; 1308 // Possible solution derived from a discussion at:
1008 m_lastAngularVelocity.Y = 0; 1309 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1310
1311 // Create a rotation that is only the vehicle's rotation around Z
1312 Vector3 currentEuler = Vector3.Zero;
1313 VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z);
1314 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z);
1315
1316 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1317 Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
1318 // Compute the angle between those to vectors.
1319 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
1320 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1321
1322 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1323 // TODO: add 'efficiency'.
1324 differenceAngle /= m_verticalAttractionTimescale;
1325
1326 // Create the quaterian representing the correction angle
1327 Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle);
1328
1329 // Turn that quaternion into Euler values to make it into velocities to apply.
1330 Vector3 vertContributionV = Vector3.Zero;
1331 correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z);
1332 vertContributionV *= -1f;
1333
1334 VehicleRotationalVelocity += vertContributionV;
1335
1336 VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
1337 Prim.LocalID,
1338 differenceAxis,
1339 differenceAngle,
1340 correctionRotation,
1341 vertContributionV);
1342
1343 // ===================================================================
1344 /*
1345 Vector3 vertContributionV = Vector3.Zero;
1346 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1347
1348 // Take a vector pointing up and convert it from world to vehicle relative coords.
1349 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
1350
1351 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1352 // is now:
1353 // leaning to one side: rotated around the X axis with the Y value going
1354 // from zero (nearly straight up) to one (completely to the side)) or
1355 // leaning front-to-back: rotated around the Y axis with the value of X being between
1356 // zero and one.
1357 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1358
1359 // Y error means needed rotation around X axis and visa versa.
1360 // Since the error goes from zero to one, the asin is the corresponding angle.
1361 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1362 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1363 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1364
1365 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1366 if (verticalError.Z < 0f)
1367 {
1368 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
1369 // vertContribution.Y -= PIOverFour;
1370 }
1371
1372 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1373 // Correction happens over a number of seconds.
1374 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1375
1376 // The correction happens over the user's time period
1377 vertContributionV /= m_verticalAttractionTimescale;
1378
1379 // Rotate the vehicle rotation to the world coordinates.
1380 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1381
1382 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
1383 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
1384 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1385 */
1010 } 1386 }
1387 }
1388
1389 // Angular correction to correct the direction the vehicle is pointing to be
1390 // the direction is should want to be pointing.
1391 // The vehicle is moving in some direction and correct its orientation to it is pointing
1392 // in that direction.
1393 // TODO: implement reference frame.
1394 public void ComputeAngularDeflection()
1395 {
1396 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1397 // approximately the same X or Y correction. When added together (when contributions are combined)
1398 // this creates an over-correction and then wabbling as the target is overshot.
1399 // TODO: rethink how the different correction computations inter-relate.
1011 1400
1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1401 if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1013 { 1402 {
1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1403 Vector3 deflectContributionV = Vector3.Zero;
1015 Prim.ZeroAngularMotion(true); 1404
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1405 // The direction the vehicle is moving
1406 Vector3 movingDirection = VehicleVelocity;
1407 movingDirection.Normalize();
1408
1409 // If the vehicle is going backward, it is still pointing forward
1410 movingDirection *= Math.Sign(VehicleForwardSpeed);
1411
1412 // The direction the vehicle is pointing
1413 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1414 pointingDirection.Normalize();
1415
1416 // The difference between what is and what should be.
1417 Vector3 deflectionError = movingDirection - pointingDirection;
1418
1419 // Don't try to correct very large errors (not our job)
1420 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1421 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1422 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1423 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1424 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1425 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1426
1427 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1428
1429 // Scale the correction by recovery timescale and efficiency
1430 deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency;
1431 deflectContributionV /= m_angularDeflectionTimescale;
1432
1433 VehicleRotationalVelocity += deflectContributionV * VehicleOrientation;
1434
1435 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1436 Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1437 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1438 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1017 } 1439 }
1018 else 1440 }
1441
1442 // Angular change to rotate the vehicle around the Z axis when the vehicle
1443 // is tipped around the X axis.
1444 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1445 // The vertical attractor feature must be enabled in order for the banking behavior to
1446 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1447 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1448 // of the yaw effect will be proportional to the
1449 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1450 // velocity along its preferred axis of motion.
1451 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1452 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1453 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1454 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1455 // Negating the banking coefficient will make it so that the vehicle leans to the
1456 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1457 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1458 // banking vehicles do what you want rather than what the laws of physics allow.
1459 // For example, consider a real motorcycle...it must be moving forward in order for
1460 // it to turn while banking, however video-game motorcycles are often configured
1461 // to turn in place when at a dead stop--because they are often easier to control
1462 // that way using the limited interface of the keyboard or game controller. The
1463 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1464 // banking by functioning as a slider between a banking that is correspondingly
1465 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1466 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1467 // to "dynamic" where the banking is also proportional to its velocity along its
1468 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1469 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1470 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1471 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1472 // make a sluggish vehicle by giving it a timescale of several seconds.
1473 public void ComputeAngularBanking()
1474 {
1475 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1019 { 1476 {
1020 // Apply to the body. 1477 Vector3 bankingContributionV = Vector3.Zero;
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless. 1478
1022 // Since we are stuffing the angular velocity directly into the object, the computed 1479 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1023 // velocity needs to be scaled by the timestep. 1480 // As the vehicle rolls to the right or left, the Y value will increase from
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); 1481 // zero (straight up) to 1 or -1 (full tilt right or left)
1025 Prim.ForceRotationalVelocity = applyAngularForce; 1482 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1026 1483
1027 // Decay the angular movement for next time 1484 // Figure out the yaw value for this much roll.
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; 1485 float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
1029 m_lastAngularVelocity *= Vector3.One - decayamount; 1486 // actual error = static turn error + dynamic turn error
1030 1487 float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", 1488
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); 1489 // TODO: the banking effect should not go to infinity but what to limit it to?
1490 // And what should happen when this is being added to a user defined yaw that is already PI*4?
1491 mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12);
1492
1493 // Build the force vector to change rotation from what it is to what it should be
1494 bankingContributionV.Z = -mixedYawAngle;
1495
1496 // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
1497 bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
1498
1499 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
1500 VehicleRotationalVelocity += bankingContributionV;
1501
1502
1503 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1504 Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1033 } 1505 }
1034 } //end MoveAngular 1506 }
1035 1507
1508 // This is from previous instantiations of XXXDynamics.cs.
1509 // Applies roll reference frame.
1510 // TODO: is this the right way to separate the code to do this operation?
1511 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1512 internal void LimitRotation(float timestep)
1037 { 1513 {
1038 Quaternion rotq = Prim.ForceOrientation; 1514 Quaternion rotq = VehicleOrientation;
1039 Quaternion m_rot = rotq; 1515 Quaternion m_rot = rotq;
1040 if (m_RollreferenceFrame != Quaternion.Identity) 1516 if (m_RollreferenceFrame != Quaternion.Identity)
1041 { 1517 {
@@ -1063,12 +1539,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1063 } 1539 }
1064 if (rotq != m_rot) 1540 if (rotq != m_rot)
1065 { 1541 {
1066 Prim.ForceOrientation = m_rot; 1542 VehicleOrientation = m_rot;
1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1543 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1068 } 1544 }
1069 1545
1070 } 1546 }
1071 1547
1548 private float ClampInRange(float low, float val, float high)
1549 {
1550 return Math.Max(low, Math.Min(val, high));
1551 // return Utils.Clamp(val, low, high);
1552 }
1553
1072 // Invoke the detailed logger and output something if it's enabled. 1554 // Invoke the detailed logger and output something if it's enabled.
1073 private void VDetailLog(string msg, params Object[] args) 1555 private void VDetailLog(string msg, params Object[] args)
1074 { 1556 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 0df4310..4ece1eb 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]";
@@ -43,11 +52,11 @@ public abstract class BSLinkset
43 Manual = 2 // linkset tied together manually (code moves all the pieces) 52 Manual = 2 // linkset tied together manually (code moves all the pieces)
44 } 53 }
45 // Create the correct type of linkset for this child 54 // Create the correct type of linkset for this child
46 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) 55 public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
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);
@@ -62,10 +71,14 @@ public abstract class BSLinkset
62 ret = new BSLinksetCompound(physScene, parent); 71 ret = new BSLinksetCompound(physScene, parent);
63 break; 72 break;
64 } 73 }
74 if (ret == null)
75 {
76 physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
77 }
65 return ret; 78 return ret;
66 } 79 }
67 80
68 public BSPhysObject LinksetRoot { get; protected set; } 81 public BSPrimLinkable LinksetRoot { get; protected set; }
69 82
70 public BSScene PhysicsScene { get; private set; } 83 public BSScene PhysicsScene { get; private set; }
71 84
@@ -73,7 +86,7 @@ public abstract class BSLinkset
73 public int LinksetID { get; private set; } 86 public int LinksetID { get; private set; }
74 87
75 // The children under the root in this linkset. 88 // The children under the root in this linkset.
76 protected HashSet<BSPhysObject> m_children; 89 protected HashSet<BSPrimLinkable> m_children;
77 90
78 // We lock the diddling of linkset classes to prevent any badness. 91 // We lock the diddling of linkset classes to prevent any badness.
79 // This locks the modification of the instances of this class. Changes 92 // This locks the modification of the instances of this class. Changes
@@ -82,27 +95,13 @@ public abstract class BSLinkset
82 95
83 // Some linksets have a preferred physical shape. 96 // Some linksets have a preferred physical shape.
84 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. 97 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
85 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 98 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
86 { 99 {
87 return BSPhysicsShapeType.SHAPE_UNKNOWN; 100 return BSPhysicsShapeType.SHAPE_UNKNOWN;
88 } 101 }
89 102
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 103 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
98 protected float m_mass; 104 public float LinksetMass { get; protected set; }
99 public float LinksetMass
100 {
101 get
102 {
103 return m_mass;
104 }
105 }
106 105
107 public virtual bool LinksetIsColliding { get { return false; } } 106 public virtual bool LinksetIsColliding { get { return false; } }
108 107
@@ -116,7 +115,7 @@ public abstract class BSLinkset
116 get { return ComputeLinksetGeometricCenter(); } 115 get { return ComputeLinksetGeometricCenter(); }
117 } 116 }
118 117
119 protected void Initialize(BSScene scene, BSPhysObject parent) 118 protected BSLinkset(BSScene scene, BSPrimLinkable parent)
120 { 119 {
121 // A simple linkset of one (no children) 120 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++; 121 LinksetID = m_nextLinksetID++;
@@ -125,22 +124,25 @@ public abstract class BSLinkset
125 m_nextLinksetID = 1; 124 m_nextLinksetID = 1;
126 PhysicsScene = scene; 125 PhysicsScene = scene;
127 LinksetRoot = parent; 126 LinksetRoot = parent;
128 m_children = new HashSet<BSPhysObject>(); 127 m_children = new HashSet<BSPrimLinkable>();
129 m_mass = parent.RawMass; 128 LinksetMass = parent.RawMass;
129 Rebuilding = false;
130
131 parent.ClearDisplacement();
130 } 132 }
131 133
132 // Link to a linkset where the child knows the parent. 134 // Link to a linkset where the child knows the parent.
133 // Parent changing should not happen so do some sanity checking. 135 // Parent changing should not happen so do some sanity checking.
134 // We return the parent's linkset so the child can track its membership. 136 // We return the parent's linkset so the child can track its membership.
135 // Called at runtime. 137 // Called at runtime.
136 public BSLinkset AddMeToLinkset(BSPhysObject child) 138 public BSLinkset AddMeToLinkset(BSPrimLinkable child)
137 { 139 {
138 lock (m_linksetActivityLock) 140 lock (m_linksetActivityLock)
139 { 141 {
140 // Don't add the root to its own linkset 142 // Don't add the root to its own linkset
141 if (!IsRoot(child)) 143 if (!IsRoot(child))
142 AddChildToLinkset(child); 144 AddChildToLinkset(child);
143 m_mass = ComputeLinksetMass(); 145 LinksetMass = ComputeLinksetMass();
144 } 146 }
145 return this; 147 return this;
146 } 148 }
@@ -149,7 +151,7 @@ public abstract class BSLinkset
149 // Returns a new linkset for the child which is a linkset of one (just the 151 // Returns a new linkset for the child which is a linkset of one (just the
150 // orphened child). 152 // orphened child).
151 // Called at runtime. 153 // Called at runtime.
152 public BSLinkset RemoveMeFromLinkset(BSPhysObject child) 154 public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child)
153 { 155 {
154 lock (m_linksetActivityLock) 156 lock (m_linksetActivityLock)
155 { 157 {
@@ -159,7 +161,7 @@ public abstract class BSLinkset
159 return this; 161 return this;
160 } 162 }
161 RemoveChildFromLinkset(child); 163 RemoveChildFromLinkset(child);
162 m_mass = ComputeLinksetMass(); 164 LinksetMass = ComputeLinksetMass();
163 } 165 }
164 166
165 // The child is down to a linkset of just itself 167 // The child is down to a linkset of just itself
@@ -167,7 +169,7 @@ public abstract class BSLinkset
167 } 169 }
168 170
169 // Return 'true' if the passed object is the root object of this linkset 171 // Return 'true' if the passed object is the root object of this linkset
170 public bool IsRoot(BSPhysObject requestor) 172 public bool IsRoot(BSPrimLinkable requestor)
171 { 173 {
172 return (requestor.LocalID == LinksetRoot.LocalID); 174 return (requestor.LocalID == LinksetRoot.LocalID);
173 } 175 }
@@ -178,14 +180,14 @@ public abstract class BSLinkset
178 public bool HasAnyChildren { get { return (m_children.Count > 0); } } 180 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
179 181
180 // Return 'true' if this child is in this linkset 182 // Return 'true' if this child is in this linkset
181 public bool HasChild(BSPhysObject child) 183 public bool HasChild(BSPrimLinkable child)
182 { 184 {
183 bool ret = false; 185 bool ret = false;
184 lock (m_linksetActivityLock) 186 lock (m_linksetActivityLock)
185 { 187 {
186 ret = m_children.Contains(child); 188 ret = m_children.Contains(child);
187 /* Safer version but the above should work 189 /* Safer version but the above should work
188 foreach (BSPhysObject bp in m_children) 190 foreach (BSPrimLinkable bp in m_children)
189 { 191 {
190 if (child.LocalID == bp.LocalID) 192 if (child.LocalID == bp.LocalID)
191 { 193 {
@@ -200,14 +202,14 @@ public abstract class BSLinkset
200 202
201 // Perform an action on each member of the linkset including root prim. 203 // Perform an action on each member of the linkset including root prim.
202 // Depends on the action on whether this should be done at taint time. 204 // Depends on the action on whether this should be done at taint time.
203 public delegate bool ForEachMemberAction(BSPhysObject obj); 205 public delegate bool ForEachMemberAction(BSPrimLinkable obj);
204 public virtual bool ForEachMember(ForEachMemberAction action) 206 public virtual bool ForEachMember(ForEachMemberAction action)
205 { 207 {
206 bool ret = false; 208 bool ret = false;
207 lock (m_linksetActivityLock) 209 lock (m_linksetActivityLock)
208 { 210 {
209 action(LinksetRoot); 211 action(LinksetRoot);
210 foreach (BSPhysObject po in m_children) 212 foreach (BSPrimLinkable po in m_children)
211 { 213 {
212 if (action(po)) 214 if (action(po))
213 break; 215 break;
@@ -218,16 +220,23 @@ public abstract class BSLinkset
218 220
219 // I am the root of a linkset and a new child is being added 221 // I am the root of a linkset and a new child is being added
220 // Called while LinkActivity is locked. 222 // Called while LinkActivity is locked.
221 protected abstract void AddChildToLinkset(BSPhysObject child); 223 protected abstract void AddChildToLinkset(BSPrimLinkable child);
222 224
223 // I am the root of a linkset and one of my children is being removed. 225 // 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. 226 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child); 227 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child);
226 228
227 // When physical properties are changed the linkset needs to recalculate 229 // When physical properties are changed the linkset needs to recalculate
228 // its internal properties. 230 // its internal properties.
229 // May be called at runtime or taint-time. 231 // May be called at runtime or taint-time.
230 public abstract void Refresh(BSPhysObject requestor); 232 public virtual void Refresh(BSPrimLinkable requestor)
233 {
234 LinksetMass = ComputeLinksetMass();
235 }
236
237 // Flag denoting the linkset is in the process of being rebuilt.
238 // Used to know not the schedule a rebuild in the middle of a rebuild.
239 protected bool Rebuilding { get; set; }
231 240
232 // The object is going dynamic (physical). Do any setup necessary 241 // The object is going dynamic (physical). Do any setup necessary
233 // for a dynamic linkset. 242 // for a dynamic linkset.
@@ -235,30 +244,26 @@ public abstract class BSLinkset
235 // has not yet been fully constructed. 244 // has not yet been fully constructed.
236 // Return 'true' if any properties updated on the passed object. 245 // Return 'true' if any properties updated on the passed object.
237 // Called at taint-time! 246 // Called at taint-time!
238 public abstract bool MakeDynamic(BSPhysObject child); 247 public abstract bool MakeDynamic(BSPrimLinkable child);
239 248
240 // The object is going static (non-physical). Do any setup necessary 249 // The object is going static (non-physical). Do any setup necessary
241 // for a static linkset. 250 // for a static linkset.
242 // Return 'true' if any properties updated on the passed object. 251 // Return 'true' if any properties updated on the passed object.
243 // Called at taint-time! 252 // Called at taint-time!
244 public abstract bool MakeStatic(BSPhysObject child); 253 public abstract bool MakeStatic(BSPrimLinkable child);
245 254
246 // Called when a parameter update comes from the physics engine for any object 255 // Called when a parameter update comes from the physics engine for any object
247 // of the linkset is received. 256 // of the linkset is received.
257 // Passed flag is update came from physics engine (true) or the user (false).
248 // Called at taint-time!! 258 // Called at taint-time!!
249 public abstract void UpdateProperties(BSPhysObject physObject); 259 public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
250 260
251 // Routine used when rebuilding the body of the root of the linkset 261 // Routine used when rebuilding the body of the root of the linkset
252 // Destroy all the constraints have have been made to root. 262 // Destroy all the constraints have have been made to root.
253 // This is called when the root body is changing. 263 // This is called when the root body is changing.
254 // Returns 'true' of something was actually removed and would need restoring 264 // Returns 'true' of something was actually removed and would need restoring
255 // Called at taint-time!! 265 // Called at taint-time!!
256 public abstract bool RemoveBodyDependencies(BSPrim child); 266 public abstract bool RemoveBodyDependencies(BSPrimLinkable child);
257
258 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
259 // this routine will restore the removed constraints.
260 // Called at taint-time!!
261 public abstract void RestoreBodyDependencies(BSPrim child);
262 267
263 // ================================================================ 268 // ================================================================
264 protected virtual float ComputeLinksetMass() 269 protected virtual float ComputeLinksetMass()
@@ -268,7 +273,7 @@ public abstract class BSLinkset
268 { 273 {
269 lock (m_linksetActivityLock) 274 lock (m_linksetActivityLock)
270 { 275 {
271 foreach (BSPhysObject bp in m_children) 276 foreach (BSPrimLinkable bp in m_children)
272 { 277 {
273 mass += bp.RawMass; 278 mass += bp.RawMass;
274 } 279 }
@@ -277,6 +282,7 @@ public abstract class BSLinkset
277 return mass; 282 return mass;
278 } 283 }
279 284
285 // Computes linkset's center of mass in world coordinates.
280 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() 286 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
281 { 287 {
282 OMV.Vector3 com; 288 OMV.Vector3 com;
@@ -285,7 +291,7 @@ public abstract class BSLinkset
285 com = LinksetRoot.Position * LinksetRoot.RawMass; 291 com = LinksetRoot.Position * LinksetRoot.RawMass;
286 float totalMass = LinksetRoot.RawMass; 292 float totalMass = LinksetRoot.RawMass;
287 293
288 foreach (BSPhysObject bp in m_children) 294 foreach (BSPrimLinkable bp in m_children)
289 { 295 {
290 com += bp.Position * bp.RawMass; 296 com += bp.Position * bp.RawMass;
291 totalMass += bp.RawMass; 297 totalMass += bp.RawMass;
@@ -304,9 +310,9 @@ public abstract class BSLinkset
304 { 310 {
305 com = LinksetRoot.Position; 311 com = LinksetRoot.Position;
306 312
307 foreach (BSPhysObject bp in m_children) 313 foreach (BSPrimLinkable bp in m_children)
308 { 314 {
309 com += bp.Position * bp.RawMass; 315 com += bp.Position;
310 } 316 }
311 com /= (m_children.Count + 1); 317 com /= (m_children.Count + 1);
312 } 318 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index b9c2cf9..e05562a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,22 +28,80 @@ 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 int Index;
44 public OMV.Vector3 OffsetFromRoot;
45 public OMV.Vector3 OffsetFromCenterOfMass;
46 public OMV.Quaternion OffsetRot;
47 public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r)
48 {
49 Index = indx;
50 OffsetFromRoot = p;
51 OffsetFromCenterOfMass = p;
52 OffsetRot = r;
53 }
54 // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape)
55 public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement)
56 {
57 // Each child position and rotation is given relative to the center-of-mass.
58 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation);
59 OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation;
60 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
61 OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation;
62
63 // Save relative position for recomputing child's world position after moving linkset.
64 Index = indx;
65 OffsetFromRoot = displacementFromRoot;
66 OffsetFromCenterOfMass = displacementFromCOM;
67 OffsetRot = displacementRot;
68 }
69 public override void Clear()
70 {
71 Index = 0;
72 OffsetFromRoot = OMV.Vector3.Zero;
73 OffsetFromCenterOfMass = OMV.Vector3.Zero;
74 OffsetRot = OMV.Quaternion.Identity;
75 }
76 public override string ToString()
77 {
78 StringBuilder buff = new StringBuilder();
79 buff.Append("<i=");
80 buff.Append(Index.ToString());
81 buff.Append(",p=");
82 buff.Append(OffsetFromRoot.ToString());
83 buff.Append(",m=");
84 buff.Append(OffsetFromCenterOfMass.ToString());
85 buff.Append(",r=");
86 buff.Append(OffsetRot.ToString());
87 buff.Append(">");
88 return buff.ToString();
89 }
90};
91
35public sealed class BSLinksetCompound : BSLinkset 92public sealed class BSLinksetCompound : BSLinkset
36{ 93{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 94 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 95
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 96 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
97 : base(scene, parent)
40 { 98 {
41 base.Initialize(scene, parent);
42 } 99 }
43 100
44 // For compound implimented linksets, if there are children, use compound shape for the root. 101 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 102 public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
46 { 103 {
104 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 105 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 106 if (IsRoot(requestor) && HasAnyChildren)
49 { 107 {
@@ -55,41 +113,57 @@ public sealed class BSLinksetCompound : BSLinkset
55 113
56 // When physical properties are changed the linkset needs to recalculate 114 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 115 // its internal properties.
58 // This is queued in the 'post taint' queue so the 116 public override void Refresh(BSPrimLinkable requestor)
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor)
61 { 117 {
62 // External request for Refresh (from BSPrim) is not necessary 118 base.Refresh(requestor);
63 // InternalRefresh(requestor); 119
120 // Something changed so do the rebuilding thing
121 // ScheduleRebuild();
64 } 122 }
65 123
66 private void InternalRefresh(BSPhysObject requestor) 124 // Schedule a refresh to happen after all the other taint processing.
125 private void ScheduleRebuild(BSPrimLinkable requestor)
67 { 126 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 127 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
69 // Queue to happen after all the other taint processing 128 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 129 // When rebuilding, it is possible to set properties that would normally require a rebuild.
130 // If already rebuilding, don't request another rebuild.
131 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
132 if (!Rebuilding && HasAnyChildren)
71 { 133 {
72 if (IsRoot(requestor) && HasAnyChildren) 134 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
73 RecomputeLinksetCompound(); 135 {
74 }); 136 if (HasAnyChildren)
137 RecomputeLinksetCompound();
138 });
139 }
75 } 140 }
76 141
77 // The object is going dynamic (physical). Do any setup necessary 142 // 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 143 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed. 144 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object. 145 // Return 'true' if any properties updated on the passed object.
82 // Called at taint-time! 146 // Called at taint-time!
83 public override bool MakeDynamic(BSPhysObject child) 147 public override bool MakeDynamic(BSPrimLinkable child)
84 { 148 {
85 bool ret = false; 149 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 150 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 151 if (IsRoot(child))
152 {
153 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
154 ScheduleRebuild(LinksetRoot);
155 }
156 else
88 { 157 {
89 // Physical children are removed from the world as the shape ofthe root compound 158 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 159 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 160 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 161 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
162 // We don't want collisions from the old linkset children.
163 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
164
165 child.PhysBody.collisionType = CollisionType.LinksetChild;
166
93 ret = true; 167 ret = true;
94 } 168 }
95 return ret; 169 return ret;
@@ -100,73 +174,181 @@ public sealed class BSLinksetCompound : BSLinkset
100 // This doesn't normally happen -- OpenSim removes the objects from the physical 174 // This doesn't normally happen -- OpenSim removes the objects from the physical
101 // world if it is a static linkset. 175 // world if it is a static linkset.
102 // Called at taint-time! 176 // Called at taint-time!
103 public override bool MakeStatic(BSPhysObject child) 177 public override bool MakeStatic(BSPrimLinkable child)
104 { 178 {
105 bool ret = false; 179 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 180 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 181 if (IsRoot(child))
182 {
183 ScheduleRebuild(LinksetRoot);
184 }
185 else
108 { 186 {
109 // The non-physical children can come back to life. 187 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 188 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 189
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 190 child.PhysBody.collisionType = CollisionType.LinksetChild;
191
192 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
193 PhysicsScene.PE.Activate(child.PhysBody, false);
113 ret = true; 194 ret = true;
114 } 195 }
115 return ret; 196 return ret;
116 } 197 }
117 198
118 // Called at taint-time!! 199 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
119 public override void UpdateProperties(BSPhysObject updated) 200 // Called at taint-time.
120 { 201 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
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 { 202 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr); 203 // The user moving a child around requires the rebuilding of the linkset compound shape
129 } 204 // One problem is this happens when a border is crossed -- the simulator implementation
205 // stores the position into the group which causes the move of the object
206 // but it also means all the child positions get updated.
207 // What would cause an unnecessary rebuild so we make sure the linkset is in a
208 // region before bothering to do a rebuild.
209 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
210 {
211 // If a child of the linkset is updating only the position or rotation, that can be done
212 // without rebuilding the linkset.
213 // If a handle for the child can be fetch, we update the child here. If a rebuild was
214 // scheduled by someone else, the rebuild will just replace this setting.
215
216 bool updatedChild = false;
217 // Anything other than updating position or orientation usually means a physical update
218 // and that is caused by us updating the object.
219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
220 {
221 // Find the physical instance of the child
222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
223 {
224 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
230 if (updated.LinksetChildIndex < numLinksetChildren)
231 {
232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex);
233 if (linksetChildShape.HasPhysicalShape)
234 {
235 // Found the child shape within the compound shape
236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex,
237 updated.RawPosition - LinksetRoot.RawPosition,
238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
239 true /* shouldRecalculateLocalAabb */);
240 updatedChild = true;
241 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
242 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
243 }
244 else // DEBUG DEBUG
245 { // DEBUG DEBUG
246 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
247 updated.LocalID, linksetChildShape);
248 } // DEBUG DEBUG
249 }
250 else // DEBUG DEBUG
251 { // DEBUG DEBUG
252 // the child is not yet in the compound shape. This is non-fatal.
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
254 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
255 } // DEBUG DEBUG
256 }
257 else // DEBUG DEBUG
258 { // DEBUG DEBUG
259 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
260 } // DEBUG DEBUG
130 261
131 public override OMV.Quaternion Orientation(BSPhysObject member) 262 if (!updatedChild)
132 { 263 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); 264 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
265 // Note: there are several ways through this code that will not update the child if
266 // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
267 // there will already be a rebuild scheduled.
268 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
269 updated.LocalID, whichUpdated);
270 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
271 ScheduleRebuild(updated);
272 }
273 }
274 }
134 } 275 }
135 276
136 // Routine called when rebuilding the body of some member of the linkset. 277 // Routine called when rebuilding the body of some member of the linkset.
137 // Since we don't keep in world relationships, do nothing unless it's a child changing. 278 // Since we don't keep in world relationships, do nothing unless it's a child changing.
138 // Returns 'true' of something was actually removed and would need restoring 279 // Returns 'true' of something was actually removed and would need restoring
139 // Called at taint-time!! 280 // Called at taint-time!!
140 public override bool RemoveBodyDependencies(BSPrim child) 281 public override bool RemoveBodyDependencies(BSPrimLinkable child)
141 { 282 {
142 bool ret = false; 283 bool ret = false;
143 284
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 285 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); 286 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
146 287
147 if (!IsRoot(child)) 288 if (!IsRoot(child))
148 { 289 {
149 // Cause the current shape to be freed and the new one to be built. 290 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 291 // its position in the linkset.
151 ret = true; 292 RecomputeChildWorldPosition(child, true /* inTaintTime */);
293 child.LinksetInfo = null;
152 } 294 }
153 295
296 // Cannot schedule a refresh/rebuild here because this routine is called when
297 // the linkset is being rebuilt.
298 // InternalRefresh(LinksetRoot);
299
154 return ret; 300 return ret;
155 } 301 }
156 302
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 303 // When the linkset is built, the child shape is added to the compound shape relative to the
158 // this routine will restore the removed constraints. 304 // root shape. The linkset then moves around but this does not move the actual child
159 // Called at taint-time!! 305 // prim. The child prim's location must be recomputed based on the location of the root shape.
160 public override void RestoreBodyDependencies(BSPrim child) 306 private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime)
161 { 307 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 308 // For the moment (20130201), disable this computation (converting the child physical addr back to
309 // a region address) until we have a good handle on center-of-mass offsets and what the physics
310 // engine moving a child actually means.
311 // The simulator keeps track of where children should be as the linkset moves. Setting
312 // the pos/rot here does not effect that knowledge as there is no good way for the
313 // physics engine to send the simulator an update for a child.
314
315 /*
316 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
317 if (lci != null)
318 {
319 if (inTaintTime)
320 {
321 OMV.Vector3 oldPos = child.RawPosition;
322 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
323 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
324 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
325 child.LocalID, oldPos, lci, child.RawPosition);
326 }
327 else
328 {
329 // TaintedObject is not used here so the raw position is set now and not at taint-time.
330 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
331 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
332 }
333 }
334 else
335 {
336 // This happens when children have been added to the linkset but the linkset
337 // has not been constructed yet. So like, at taint time, adding children to a linkset
338 // and then changing properties of the children (makePhysical, for instance)
339 // but the post-print action of actually rebuilding the linkset has not yet happened.
340 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
341 // LogHeader, child.LocalID);
342 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
343 }
344 */
163 } 345 }
164 346
165 // ================================================================ 347 // ================================================================
166 348
167 // Add a new child to the linkset. 349 // Add a new child to the linkset.
168 // Called while LinkActivity is locked. 350 // Called while LinkActivity is locked.
169 protected override void AddChildToLinkset(BSPhysObject child) 351 protected override void AddChildToLinkset(BSPrimLinkable child)
170 { 352 {
171 if (!HasChild(child)) 353 if (!HasChild(child))
172 { 354 {
@@ -174,24 +356,28 @@ public sealed class BSLinksetCompound : BSLinkset
174 356
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 357 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176 358
177 // Cause constraints and assorted properties to be recomputed before the next simulation step. 359 // Rebuild the compound shape with the new child shape included
178 InternalRefresh(LinksetRoot); 360 ScheduleRebuild(child);
179 } 361 }
180 return; 362 return;
181 } 363 }
182 364
183 // Remove the specified child from the linkset. 365 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 366 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 367 protected override void RemoveChildFromLinkset(BSPrimLinkable child)
186 { 368 {
369 child.ClearDisplacement();
370
187 if (m_children.Remove(child)) 371 if (m_children.Remove(child))
188 { 372 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 373 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID, 374 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), 375 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 376 child.LocalID, child.PhysBody.AddrString);
193 377
194 // Cause the child's body to be rebuilt and thus restored to normal operation 378 // Cause the child's body to be rebuilt and thus restored to normal operation
379 RecomputeChildWorldPosition(child, false);
380 child.LinksetInfo = null;
195 child.ForceBodyShapeRebuild(false); 381 child.ForceBodyShapeRebuild(false);
196 382
197 if (!HasAnyChildren) 383 if (!HasAnyChildren)
@@ -201,8 +387,8 @@ public sealed class BSLinksetCompound : BSLinkset
201 } 387 }
202 else 388 else
203 { 389 {
204 // Schedule a rebuild of the linkset before the next simulation tick. 390 // Rebuild the compound shape with the child removed
205 InternalRefresh(LinksetRoot); 391 ScheduleRebuild(LinksetRoot);
206 } 392 }
207 } 393 }
208 return; 394 return;
@@ -213,63 +399,116 @@ public sealed class BSLinksetCompound : BSLinkset
213 // Constraint linksets are rebuilt every time. 399 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart. 400 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!! 401 // Called at taint time!!
402 private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged
216 private void RecomputeLinksetCompound() 403 private void RecomputeLinksetCompound()
217 { 404 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 405 try
219 LinksetRoot.ForceBodyShapeRebuild(true); 406 {
407 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.)
408 Rebuilding = true;
220 409
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 410 // Cause the root shape to be rebuilt as a compound object with just the root in it
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 411 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */);
223 412
224 // Add a shape for each of the other children in the linkset 413 // The center of mass for the linkset is the geometric center of the group.
225 ForEachMember(delegate(BSPhysObject cPrim) 414 // Compute a displacement for each component so it is relative to the center-of-mass.
226 { 415 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
227 if (!IsRoot(cPrim)) 416 OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
417 if (!disableCOM) // DEBUG DEBUG
228 { 418 {
229 // Each child position and rotation is given relative to the root. 419 // Compute a center-of-mass in world coordinates.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 420 centerOfMassW = ComputeLinksetCenterOfMass();
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; 421 }
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; 422
423 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
424
425 // 'centerDisplacement' is the value to subtract from children to give physical offset position
426 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
427 LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement);
233 428
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 429 // This causes the physical position of the root prim to be offset to accomodate for the displacements
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
236 431
237 if (cPrim.PhysShape.isNativeShape) 432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */,
434 -centerDisplacement,
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
437
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
440
441 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
442 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
443
444 // Add a shape for each of the other children in the linkset
445 int memberIndex = 1;
446 ForEachMember(delegate(BSPrimLinkable cPrim)
447 {
448 if (IsRoot(cPrim))
238 { 449 {
239 // Native shapes are not shared so we need to create a new one. 450 cPrim.LinksetChildIndex = 0;
240 // A mesh or hull is created because scale is not available on a native shape.
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
242 BulletShape saveShape = cPrim.PhysShape;
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape
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 } 451 }
249 else 452 else
250 { 453 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 454 cPrim.LinksetChildIndex = memberIndex;
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 455
456 if (cPrim.PhysShape.isNativeShape)
253 { 457 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 458 // A native shape is turned into a hull collision shape because native
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 459 // shapes are not shared so we have to hullify it so it will be tracked
460 // and freed at the correct time. This also solves the scaling problem
461 // (native shapes scale but hull/meshes are assumed to not be).
462 // TODO: decide of the native shape can just be used in the compound shape.
463 // Use call to CreateGeomNonSpecial().
464 BulletShape saveShape = cPrim.PhysShape;
465 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
466 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
467 BulletShape newShape = cPrim.PhysShape;
468 cPrim.PhysShape = saveShape;
469
470 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
471 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
472 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
473 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
474 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
256 } 475 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); 476 else
258 } 477 {
259 } 478 // For the shared shapes (meshes and hulls), just use the shape in the child.
260 return false; // 'false' says to move onto the next child in the list 479 // The reference count added here will be decremented when the compound shape
261 }); 480 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
481 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
482 {
483 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
484 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
485 }
486 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
487 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
488 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
489 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
490 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
262 491
263 // With all of the linkset packed into the root prim, it has the mass of everyone. 492 }
264 float linksetMass = LinksetMass; 493 memberIndex++;
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 494 }
495 return false; // 'false' says to move onto the next child in the list
496 });
266 497
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 498 // With all of the linkset packed into the root prim, it has the mass of everyone.
499 LinksetMass = ComputeLinksetMass();
500 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
268 501
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. 502 // Enable the physical position updator to return the position and rotation of the root shape
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, 503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); 504 }
505 finally
506 {
507 Rebuilding = false;
508 }
272 509
510 // See that the Aabb surrounds the new shape
511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
273 } 512 }
274} 513}
275} \ No newline at end of file 514} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index c855fda..6d252ca 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -36,23 +36,27 @@ 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, BSPrimLinkable 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
45 // its internal properties. 44 // its internal properties.
46 // This is queued in the 'post taint' queue so the 45 // This is queued in the 'post taint' queue so the
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(BSPrimLinkable 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
@@ -61,7 +65,7 @@ public sealed class BSLinksetConstraints : BSLinkset
61 // has not yet been fully constructed. 65 // has not yet been fully constructed.
62 // Return 'true' if any properties updated on the passed object. 66 // Return 'true' if any properties updated on the passed object.
63 // Called at taint-time! 67 // Called at taint-time!
64 public override bool MakeDynamic(BSPhysObject child) 68 public override bool MakeDynamic(BSPrimLinkable child)
65 { 69 {
66 // What is done for each object in BSPrim is what we want. 70 // What is done for each object in BSPrim is what we want.
67 return false; 71 return false;
@@ -72,41 +76,29 @@ public sealed class BSLinksetConstraints : BSLinkset
72 // This doesn't normally happen -- OpenSim removes the objects from the physical 76 // This doesn't normally happen -- OpenSim removes the objects from the physical
73 // world if it is a static linkset. 77 // world if it is a static linkset.
74 // Called at taint-time! 78 // Called at taint-time!
75 public override bool MakeStatic(BSPhysObject child) 79 public override bool MakeStatic(BSPrimLinkable child)
76 { 80 {
77 // What is done for each object in BSPrim is what we want. 81 // What is done for each object in BSPrim is what we want.
78 return false; 82 return false;
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(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
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.
102 // Returns 'true' of something was actually removed and would need restoring 94 // Returns 'true' of something was actually removed and would need restoring
103 // Called at taint-time!! 95 // Called at taint-time!!
104 public override bool RemoveBodyDependencies(BSPrim child) 96 public override bool RemoveBodyDependencies(BSPrimLinkable child)
105 { 97 {
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 {
@@ -118,19 +110,11 @@ public sealed class BSLinksetConstraints : BSLinkset
118 return ret; 110 return ret;
119 } 111 }
120 112
121 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
122 // this routine will restore the removed constraints.
123 // Called at taint-time!!
124 public override void RestoreBodyDependencies(BSPrim child)
125 {
126 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
127 }
128
129 // ================================================================ 113 // ================================================================
130 114
131 // Add a new child to the linkset. 115 // Add a new child to the linkset.
132 // Called while LinkActivity is locked. 116 // Called while LinkActivity is locked.
133 protected override void AddChildToLinkset(BSPhysObject child) 117 protected override void AddChildToLinkset(BSPrimLinkable child)
134 { 118 {
135 if (!HasChild(child)) 119 if (!HasChild(child))
136 { 120 {
@@ -146,17 +130,17 @@ public sealed class BSLinksetConstraints : BSLinkset
146 130
147 // Remove the specified child from the linkset. 131 // Remove the specified child from the linkset.
148 // Safe to call even if the child is not really in my linkset. 132 // Safe to call even if the child is not really in my linkset.
149 protected override void RemoveChildFromLinkset(BSPhysObject child) 133 protected override void RemoveChildFromLinkset(BSPrimLinkable child)
150 { 134 {
151 if (m_children.Remove(child)) 135 if (m_children.Remove(child))
152 { 136 {
153 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now 137 BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
154 BSPhysObject childx = child; 138 BSPrimLinkable childx = child;
155 139
156 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 140 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
157 childx.LocalID, 141 childx.LocalID,
158 rootx.LocalID, rootx.PhysBody.ptr.ToString("X"), 142 rootx.LocalID, rootx.PhysBody.AddrString,
159 childx.LocalID, childx.PhysBody.ptr.ToString("X")); 143 childx.LocalID, childx.PhysBody.AddrString);
160 144
161 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() 145 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
162 { 146 {
@@ -175,13 +159,13 @@ public sealed class BSLinksetConstraints : BSLinkset
175 159
176 // Create a constraint between me (root of linkset) and the passed prim (the child). 160 // Create a constraint between me (root of linkset) and the passed prim (the child).
177 // Called at taint time! 161 // Called at taint time!
178 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) 162 private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
179 { 163 {
180 // Don't build the constraint when asked. Put it off until just before the simulation step. 164 // Don't build the constraint when asked. Put it off until just before the simulation step.
181 Refresh(rootPrim); 165 Refresh(rootPrim);
182 } 166 }
183 167
184 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) 168 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
185 { 169 {
186 // Zero motion for children so they don't interpolate 170 // Zero motion for children so they don't interpolate
187 childPrim.ZeroMotion(true); 171 childPrim.ZeroMotion(true);
@@ -195,8 +179,8 @@ public sealed class BSLinksetConstraints : BSLinkset
195 179
196 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", 180 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
197 rootPrim.LocalID, 181 rootPrim.LocalID,
198 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), 182 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
199 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"), 183 childPrim.LocalID, childPrim.PhysBody.AddrString,
200 rootPrim.Position, childPrim.Position, midPoint); 184 rootPrim.Position, childPrim.Position, midPoint);
201 185
202 // create a constraint that allows no freedom of movement between the two objects 186 // create a constraint that allows no freedom of movement between the two objects
@@ -239,14 +223,14 @@ public sealed class BSLinksetConstraints : BSLinkset
239 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); 223 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
240 224
241 // tweek the constraint to increase stability 225 // tweek the constraint to increase stability
242 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); 226 constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset);
243 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), 227 constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor,
244 PhysicsScene.Params.linkConstraintTransMotorMaxVel, 228 BSParam.LinkConstraintTransMotorMaxVel,
245 PhysicsScene.Params.linkConstraintTransMotorMaxForce); 229 BSParam.LinkConstraintTransMotorMaxForce);
246 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); 230 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
247 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) 231 if (BSParam.LinkConstraintSolverIterations != 0f)
248 { 232 {
249 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); 233 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
250 } 234 }
251 return constrain; 235 return constrain;
252 } 236 }
@@ -255,19 +239,19 @@ public sealed class BSLinksetConstraints : BSLinkset
255 // The root and child bodies are passed in because we need to remove the constraint between 239 // The root and child bodies are passed in because we need to remove the constraint between
256 // the bodies that were present at unlink time. 240 // the bodies that were present at unlink time.
257 // Called at taint time! 241 // Called at taint time!
258 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) 242 private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
259 { 243 {
260 bool ret = false; 244 bool ret = false;
261 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", 245 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
262 rootPrim.LocalID, 246 rootPrim.LocalID,
263 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), 247 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
264 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X")); 248 childPrim.LocalID, childPrim.PhysBody.AddrString);
265 249
266 // Find the constraint for this link and get rid of it from the overall collection and from my list 250 // 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)) 251 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
268 { 252 {
269 // Make the child refresh its location 253 // Make the child refresh its location
270 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); 254 PhysicsScene.PE.PushUpdate(childPrim.PhysBody);
271 ret = true; 255 ret = true;
272 } 256 }
273 257
@@ -277,7 +261,7 @@ public sealed class BSLinksetConstraints : BSLinkset
277 // Remove linkage between myself and any possible children I might have. 261 // Remove linkage between myself and any possible children I might have.
278 // Returns 'true' of any constraints were destroyed. 262 // Returns 'true' of any constraints were destroyed.
279 // Called at taint time! 263 // Called at taint time!
280 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) 264 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
281 { 265 {
282 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 266 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
283 267
@@ -292,20 +276,17 @@ public sealed class BSLinksetConstraints : BSLinkset
292 private void RecomputeLinksetConstraints() 276 private void RecomputeLinksetConstraints()
293 { 277 {
294 float linksetMass = LinksetMass; 278 float linksetMass = LinksetMass;
295 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 279 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
296 280
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}", 281 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
301 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass); 282 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
302 283
303 foreach (BSPhysObject child in m_children) 284 foreach (BSPrimLinkable child in m_children)
304 { 285 {
305 // A child in the linkset physically shows the mass of the whole linkset. 286 // 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. 287 // 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.) 288 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
308 child.UpdatePhysicalMassProperties(linksetMass); 289 child.UpdatePhysicalMassProperties(linksetMass, true);
309 290
310 BSConstraint constrain; 291 BSConstraint constrain;
311 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) 292 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
@@ -315,11 +296,7 @@ public sealed class BSLinksetConstraints : BSLinkset
315 } 296 }
316 constrain.RecomputeConstraintVariables(linksetMass); 297 constrain.RecomputeConstraintVariables(linksetMass);
317 298
318 // DEBUG: see of inter-linkset collisions are causing problems 299 // 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 } 300 }
324 301
325 } 302 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
new file mode 100755
index 0000000..ee77d6e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -0,0 +1,203 @@
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 // Get the current attribute values for this material
184 MaterialAttributes thisAttrib = Attributes[matType];
185 // Find the field for the passed attribute name (eg, find field named 'friction')
186 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
187 if (fieldInfo != null)
188 {
189 fieldInfo.SetValue(thisAttrib, val);
190 // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
191 Attributes[matType] = thisAttrib;
192 }
193 }
194
195 // Given a material type, return a structure of attributes.
196 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
197 {
198 int ind = (int)type;
199 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
200 return Attributes[ind];
201 }
202}
203}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index bc6e4c4..9501e2d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,104 +1,486 @@
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 // Returns the correction needed to move 'current' to 'target'.
143 public virtual Vector3 Step(float timeStep)
144 {
145 if (!Enabled) return TargetValue;
146
147 Vector3 origTarget = TargetValue; // DEBUG
148 Vector3 origCurrVal = CurrentValue; // DEBUG
149
150 Vector3 correction = Vector3.Zero;
151 Vector3 error = TargetValue - CurrentValue;
152 LastError = error;
153 if (!ErrorIsZero(error))
154 {
155 correction = StepError(timeStep, error);
156
157 CurrentValue += correction;
158
159 // The desired value reduces to zero which also reduces the difference with current.
160 // If the decay time is infinite, don't decay at all.
161 float decayFactor = 0f;
162 if (TargetValueDecayTimeScale != BSMotor.Infinite)
163 {
164 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
165 TargetValue *= (1f - decayFactor);
166 }
167
168 // The amount we can correct the error is reduced by the friction
169 Vector3 frictionFactor = Vector3.Zero;
170 if (FrictionTimescale != BSMotor.InfiniteVector)
171 {
172 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
173 // Individual friction components can be 'infinite' so compute each separately.
174 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
175 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
176 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
177 frictionFactor *= timeStep;
178 CurrentValue *= (Vector3.One - frictionFactor);
179 }
180
181 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
182 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
183 timeStep, error, correction);
184 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
185 BSScene.DetailLogZero, UseName,
186 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
187 TargetValue, CurrentValue);
188 }
189 else
190 {
191 // Difference between what we have and target is small. Motor is done.
192 if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
193 {
194 // The target can step down to nearly zero but not get there. If close to zero
195 // it is really zero.
196 TargetValue = Vector3.Zero;
197 }
198 CurrentValue = TargetValue;
199 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
200 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
201 }
202
203 return correction;
204 }
205 // version of step that sets the current value before doing the step
206 public virtual Vector3 Step(float timeStep, Vector3 current)
207 {
208 CurrentValue = current;
209 return Step(timeStep);
210 }
211 public virtual Vector3 StepError(float timeStep, Vector3 error)
212 {
213 if (!Enabled) return Vector3.Zero;
214
215 Vector3 returnCorrection = Vector3.Zero;
216 if (!ErrorIsZero(error))
217 {
218 // correction = error / secondsItShouldTakeToCorrect
219 Vector3 correctionAmount;
220 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
221 correctionAmount = error * timeStep;
222 else
223 correctionAmount = error / TimeScale * timeStep;
224
225 returnCorrection = correctionAmount;
226 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
227 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
228 }
229 return returnCorrection;
230 }
231
232 // The user sets all the parameters and calls this which outputs values until error is zero.
233 public override void GenerateTestOutput(float timeStep)
234 {
235 // maximum number of outputs to generate.
236 int maxOutput = 50;
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
238 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
239 BSScene.DetailLogZero, UseName,
240 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency,
241 CurrentValue, TargetValue);
242
243 LastError = BSMotor.InfiniteVector;
244 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
245 {
246 Vector3 lastStep = Step(timeStep);
247 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
248 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
249 }
250 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
251
252
253 }
254
255 public override string ToString()
256 {
257 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
258 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
259 }
260}
261
262// ============================================================================
263// ============================================================================
264public class BSFMotor : BSMotor
265{
266 public virtual float TimeScale { get; set; }
267 public virtual float TargetValueDecayTimeScale { get; set; }
268 public virtual float FrictionTimescale { get; set; }
269 public virtual float Efficiency { get; set; }
270
271 public virtual float ErrorZeroThreshold { get; set; }
272
273 public virtual float TargetValue { get; protected set; }
274 public virtual float CurrentValue { get; protected set; }
275 public virtual float LastError { get; protected set; }
276
277 public virtual bool ErrorIsZero()
278 {
279 return ErrorIsZero(LastError);
280 }
281 public virtual bool ErrorIsZero(float err)
282 {
283 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
284 }
285
286 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
287 : base(useName)
288 {
289 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
290 Efficiency = 1f;
291 FrictionTimescale = BSMotor.Infinite;
292 CurrentValue = TargetValue = 0f;
293 ErrorZeroThreshold = 0.01f;
294 }
295 public void SetCurrent(float current)
296 {
297 CurrentValue = current;
298 }
299 public void SetTarget(float target)
300 {
301 TargetValue = target;
302 }
303 public override void Zero()
304 {
305 base.Zero();
306 CurrentValue = TargetValue = 0f;
307 }
308
309 public virtual float Step(float timeStep)
310 {
311 if (!Enabled) return TargetValue;
312
313 float origTarget = TargetValue; // DEBUG
314 float origCurrVal = CurrentValue; // DEBUG
315
316 float correction = 0f;
317 float error = TargetValue - CurrentValue;
318 LastError = error;
319 if (!ErrorIsZero(error))
320 {
321 correction = StepError(timeStep, error);
322
323 CurrentValue += correction;
324
325 // The desired value reduces to zero which also reduces the difference with current.
326 // If the decay time is infinite, don't decay at all.
327 float decayFactor = 0f;
328 if (TargetValueDecayTimeScale != BSMotor.Infinite)
329 {
330 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
331 TargetValue *= (1f - decayFactor);
332 }
333
334 // The amount we can correct the error is reduced by the friction
335 float frictionFactor = 0f;
336 if (FrictionTimescale != BSMotor.Infinite)
337 {
338 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
339 // Individual friction components can be 'infinite' so compute each separately.
340 frictionFactor = 1f / FrictionTimescale;
341 frictionFactor *= timeStep;
342 CurrentValue *= (1f - frictionFactor);
343 }
344
345 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
346 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
347 timeStep, error, correction);
348 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
349 BSScene.DetailLogZero, UseName,
350 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
351 TargetValue, CurrentValue);
352 }
353 else
354 {
355 // Difference between what we have and target is small. Motor is done.
356 if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold))
357 {
358 // The target can step down to nearly zero but not get there. If close to zero
359 // it is really zero.
360 TargetValue = 0f;
361 }
362 CurrentValue = TargetValue;
363 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
364 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
365 }
366
367 return CurrentValue;
368 }
369
370 public virtual float StepError(float timeStep, float error)
371 {
372 if (!Enabled) return 0f;
373
374 float returnCorrection = 0f;
375 if (!ErrorIsZero(error))
376 {
377 // correction = error / secondsItShouldTakeToCorrect
378 float correctionAmount;
379 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
380 correctionAmount = error * timeStep;
381 else
382 correctionAmount = error / TimeScale * timeStep;
383
384 returnCorrection = correctionAmount;
385 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
386 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
387 }
388 return returnCorrection;
389 }
390
391 public override string ToString()
392 {
393 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
394 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
395 }
396
397}
398
399// ============================================================================
400// ============================================================================
401// Proportional, Integral, Derivitive Motor
402// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
403public class BSPIDVMotor : BSVMotor
404{
405 // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
406 public Vector3 proportionFactor { get; set; }
407 public Vector3 integralFactor { get; set; }
408 public Vector3 derivFactor { get; set; }
409
410 // The factors are vectors for the three dimensions. This is the proportional of each
411 // that is applied. This could be multiplied through the actual factors but it
412 // is sometimes easier to manipulate the factors and their mix separately.
413 // to
414 public Vector3 FactorMix;
415
416 // Arbritrary factor range.
417 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
418 public float EfficiencyHigh = 0.4f;
419 public float EfficiencyLow = 4.0f;
420
421 // Running integration of the error
422 Vector3 RunningIntegration { get; set; }
423
424 public BSPIDVMotor(string useName)
425 : base(useName)
426 {
427 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
428 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
429 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
430 FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
431 RunningIntegration = Vector3.Zero;
432 LastError = Vector3.Zero;
433 }
434
435 public override void Zero()
436 {
437 base.Zero();
438 }
439
440 public override float Efficiency
441 {
442 get { return base.Efficiency; }
443 set
444 {
445 base.Efficiency = Util.Clamp(value, 0f, 1f);
446
447 // Compute factors based on efficiency.
448 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
449 // If efficiency is low (0f), use a factor value that overcorrects.
450 // TODO: might want to vary contribution of different factor depending on efficiency.
451 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
452 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
453
454 proportionFactor = new Vector3(factor, factor, factor);
455 integralFactor = new Vector3(factor, factor, factor);
456 derivFactor = new Vector3(factor, factor, factor);
457
458 MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
459 }
460 }
461
462 // Advance the PID computation on this error.
463 public override Vector3 StepError(float timeStep, Vector3 error)
464 {
465 if (!Enabled) return Vector3.Zero;
466
467 // Add up the error so we can integrate over the accumulated errors
468 RunningIntegration += error * timeStep;
469
470 // A simple derivitive is the rate of change from the last error.
471 Vector3 derivitive = (error - LastError) * timeStep;
472 LastError = error;
473
474 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
475 Vector3 ret = error * timeStep * proportionFactor * FactorMix.X
476 + RunningIntegration * integralFactor * FactorMix.Y
477 + derivitive * derivFactor * FactorMix.Z
478 ;
479
480 MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}",
481 BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret);
482
483 return ret;
484 }
485}
486}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
new file mode 100755
index 0000000..385ed9e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -0,0 +1,815 @@
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 private static string LogHeader = "[BULLETSIM PARAMETERS]";
41
42 // Tuning notes:
43 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
44 // Contact points can be added even if the distance is positive. The constraint solver can deal with
45 // contacts with positive distances as well as negative (penetration). Contact points are discarded
46 // if the distance exceeds a certain threshold.
47 // Bullet has a contact processing threshold and a contact breaking threshold.
48 // If the distance is larger than the contact breaking threshold, it will be removed after one frame.
49 // If the distance is larger than the contact processing threshold, the constraint solver will ignore it.
50
51 // This is separate/independent from the collision margin. The collision margin increases the object a bit
52 // to improve collision detection performance and accuracy.
53 // ===================
54 // From:
55
56 // Level of Detail values kept as float because that's what the Meshmerizer wants
57 public static float MeshLOD { get; private set; }
58 public static float MeshCircularLOD { get; private set; }
59 public static float MeshMegaPrimLOD { get; private set; }
60 public static float MeshMegaPrimThreshold { get; private set; }
61 public static float SculptLOD { get; private set; }
62
63 public static int CrossingFailuresBeforeOutOfBounds { get; private set; }
64 public static float UpdateVelocityChangeThreshold { get; private set; }
65
66 public static float MinimumObjectMass { get; private set; }
67 public static float MaximumObjectMass { get; private set; }
68 public static float MaxLinearVelocity { get; private set; }
69 public static float MaxLinearVelocitySquared { get; private set; }
70 public static float MaxAngularVelocity { get; private set; }
71 public static float MaxAngularVelocitySquared { get; private set; }
72 public static float MaxAddForceMagnitude { get; private set; }
73 public static float MaxAddForceMagnitudeSquared { get; private set; }
74 public static float DensityScaleFactor { get; private set; }
75
76 public static float LinearDamping { get; private set; }
77 public static float AngularDamping { get; private set; }
78 public static float DeactivationTime { get; private set; }
79 public static float LinearSleepingThreshold { get; private set; }
80 public static float AngularSleepingThreshold { get; private set; }
81 public static float CcdMotionThreshold { get; private set; }
82 public static float CcdSweptSphereRadius { get; private set; }
83 public static float ContactProcessingThreshold { get; private set; }
84
85 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
86 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
87 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
88 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
89
90 public static float TerrainImplementation { get; private set; }
91 public static int TerrainMeshMagnification { get; private set; }
92 public static float TerrainFriction { get; private set; }
93 public static float TerrainHitFraction { get; private set; }
94 public static float TerrainRestitution { get; private set; }
95 public static float TerrainContactProcessingThreshold { get; private set; }
96 public static float TerrainCollisionMargin { get; private set; }
97
98 public static float DefaultFriction { get; private set; }
99 public static float DefaultDensity { get; private set; }
100 public static float DefaultRestitution { get; private set; }
101 public static float CollisionMargin { get; private set; }
102 public static float Gravity { get; private set; }
103
104 // Physics Engine operation
105 public static float MaxPersistantManifoldPoolSize { get; private set; }
106 public static float MaxCollisionAlgorithmPoolSize { get; private set; }
107 public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; }
108 public static bool ShouldForceUpdateAllAabbs { get; private set; }
109 public static bool ShouldRandomizeSolverOrder { get; private set; }
110 public static bool ShouldSplitSimulationIslands { get; private set; }
111 public static bool ShouldEnableFrictionCaching { get; private set; }
112 public static float NumberOfSolverIterations { get; private set; }
113 public static bool UseSingleSidedMeshes { get; private set; }
114 public static float GlobalContactBreakingThreshold { get; private set; }
115
116 // Avatar parameters
117 public static float AvatarFriction { get; private set; }
118 public static float AvatarStandingFriction { get; private set; }
119 public static float AvatarAlwaysRunFactor { get; private set; }
120 public static float AvatarDensity { get; private set; }
121 public static float AvatarRestitution { get; private set; }
122 public static float AvatarCapsuleWidth { get; private set; }
123 public static float AvatarCapsuleDepth { get; private set; }
124 public static float AvatarCapsuleHeight { get; private set; }
125 public static float AvatarContactProcessingThreshold { get; private set; }
126 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
127 public static float AvatarStepHeight { get; private set; }
128 public static float AvatarStepApproachFactor { get; private set; }
129 public static float AvatarStepForceFactor { get; private set; }
130
131 // Vehicle parameters
132 public static float VehicleMaxLinearVelocity { get; private set; }
133 public static float VehicleMaxLinearVelocitySquared { get; private set; }
134 public static float VehicleMaxAngularVelocity { get; private set; }
135 public static float VehicleMaxAngularVelocitySq { get; private set; }
136 public static float VehicleAngularDamping { get; private set; }
137 public static float VehicleFriction { get; private set; }
138 public static float VehicleRestitution { get; private set; }
139 public static Vector3 VehicleLinearFactor { get; private set; }
140 public static Vector3 VehicleAngularFactor { get; private set; }
141 public static float VehicleGroundGravityFudge { get; private set; }
142 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
143 public static bool VehicleDebuggingEnabled { get; private set; }
144
145 // Convex Hulls
146 public static int CSHullMaxDepthSplit { get; private set; }
147 public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
148 public static float CSHullConcavityThresholdPercent { get; private set; }
149 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
150 public static int CSHullMaxVertices { get; private set; }
151 public static float CSHullMaxSkinWidth { get; private set; }
152
153 // Linkset implementation parameters
154 public static float LinksetImplementation { get; private set; }
155 public static bool LinkConstraintUseFrameOffset { get; private set; }
156 public static bool LinkConstraintEnableTransMotor { get; private set; }
157 public static float LinkConstraintTransMotorMaxVel { get; private set; }
158 public static float LinkConstraintTransMotorMaxForce { get; private set; }
159 public static float LinkConstraintERP { get; private set; }
160 public static float LinkConstraintCFM { get; private set; }
161 public static float LinkConstraintSolverIterations { get; private set; }
162
163 public static float PID_D { get; private set; } // derivative
164 public static float PID_P { get; private set; } // proportional
165
166 // Various constants that come from that other virtual world that shall not be named.
167 public const float MinGravityZ = -1f;
168 public const float MaxGravityZ = 28f;
169 public const float MinFriction = 0f;
170 public const float MaxFriction = 255f;
171 public const float MinDensity = 0.01f;
172 public const float MaxDensity = 22587f;
173 public const float MinRestitution = 0f;
174 public const float MaxRestitution = 1f;
175
176 // =====================================================================================
177 // =====================================================================================
178
179 // Base parameter definition that gets and sets parameter values via a string
180 public abstract class ParameterDefnBase
181 {
182 public string name; // string name of the parameter
183 public string desc; // a short description of what the parameter means
184 public ParameterDefnBase(string pName, string pDesc)
185 {
186 name = pName;
187 desc = pDesc;
188 }
189 // Set the parameter value to the default
190 public abstract void AssignDefault(BSScene s);
191 // Get the value as a string
192 public abstract string GetValue(BSScene s);
193 // Set the value to this string value
194 public abstract void SetValue(BSScene s, string valAsString);
195 // set the value on a particular object (usually sets in physics engine)
196 public abstract void SetOnObject(BSScene s, BSPhysObject obj);
197 public abstract bool HasSetOnObject { get; }
198 }
199
200 // Specific parameter definition for a parameter of a specific type.
201 public delegate T PGetValue<T>(BSScene s);
202 public delegate void PSetValue<T>(BSScene s, T val);
203 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
204 public sealed class ParameterDefn<T> : ParameterDefnBase
205 {
206 private T defaultValue;
207 private PSetValue<T> setter;
208 private PGetValue<T> getter;
209 private PSetOnObject<T> objectSet;
210 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
211 : base(pName, pDesc)
212 {
213 defaultValue = pDefault;
214 setter = pSetter;
215 getter = pGetter;
216 objectSet = null;
217 }
218 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter, PSetOnObject<T> pObjSetter)
219 : base(pName, pDesc)
220 {
221 defaultValue = pDefault;
222 setter = pSetter;
223 getter = pGetter;
224 objectSet = pObjSetter;
225 }
226 /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work
227 public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc)
228 : base(pName, pDesc)
229 {
230 defaultValue = pDefault;
231 setter = (s, v) => { loc = v; };
232 getter = (s) => { return loc; };
233 objectSet = null;
234 }
235 */
236 public override void AssignDefault(BSScene s)
237 {
238 setter(s, defaultValue);
239 }
240 public override string GetValue(BSScene s)
241 {
242 return getter(s).ToString();
243 }
244 public override void SetValue(BSScene s, string valAsString)
245 {
246 // Get the generic type of the setter
247 Type genericType = setter.GetType().GetGenericArguments()[0];
248 // Find the 'Parse' method on that type
249 System.Reflection.MethodInfo parser = null;
250 try
251 {
252 parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } );
253 }
254 catch (Exception e)
255 {
256 s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e);
257 parser = null;
258 }
259 if (parser != null)
260 {
261 // Parse the input string
262 try
263 {
264 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
265 // Store the parsed value
266 setter(s, setValue);
267 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
268 }
269 catch
270 {
271 s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType);
272 }
273 }
274 else
275 {
276 s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType);
277 }
278 }
279 public override bool HasSetOnObject
280 {
281 get { return objectSet != null; }
282 }
283 public override void SetOnObject(BSScene s, BSPhysObject obj)
284 {
285 if (objectSet != null)
286 objectSet(s, obj);
287 }
288 }
289
290 // List of all of the externally visible parameters.
291 // For each parameter, this table maps a text name to getter and setters.
292 // To add a new externally referencable/settable parameter, add the paramter storage
293 // location somewhere in the program and make an entry in this table with the
294 // getters and setters.
295 // It is easiest to find an existing definition and copy it.
296 //
297 // A ParameterDefn<T>() takes the following parameters:
298 // -- the text name of the parameter. This is used for console input and ini file.
299 // -- a short text description of the parameter. This shows up in the console listing.
300 // -- a default value
301 // -- a delegate for getting the value
302 // -- a delegate for setting the value
303 // -- an optional delegate to update the value in the world. Most often used to
304 // push the new value to an in-world object.
305 //
306 // The single letter parameters for the delegates are:
307 // s = BSScene
308 // o = BSPhysObject
309 // v = value (appropriate type)
310 private static ParameterDefnBase[] ParameterDefinitions =
311 {
312 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties",
313 true,
314 (s) => { return ShouldMeshSculptedPrim; },
315 (s,v) => { ShouldMeshSculptedPrim = v; } ),
316 new ParameterDefn<bool>("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
317 false,
318 (s) => { return ShouldForceSimplePrimMeshing; },
319 (s,v) => { ShouldForceSimplePrimMeshing = v; } ),
320 new ParameterDefn<bool>("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
321 true,
322 (s) => { return ShouldUseHullsForPhysicalObjects; },
323 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ),
324 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
325 true,
326 (s) => { return ShouldRemoveZeroWidthTriangles; },
327 (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ),
328
329 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
330 5,
331 (s) => { return CrossingFailuresBeforeOutOfBounds; },
332 (s,v) => { CrossingFailuresBeforeOutOfBounds = v; } ),
333 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator",
334 0.1f,
335 (s) => { return UpdateVelocityChangeThreshold; },
336 (s,v) => { UpdateVelocityChangeThreshold = v; } ),
337
338 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
339 32f,
340 (s) => { return MeshLOD; },
341 (s,v) => { MeshLOD = v; } ),
342 new ParameterDefn<float>("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes",
343 32f,
344 (s) => { return MeshCircularLOD; },
345 (s,v) => { MeshCircularLOD = v; } ),
346 new ParameterDefn<float>("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
347 10f,
348 (s) => { return MeshMegaPrimThreshold; },
349 (s,v) => { MeshMegaPrimThreshold = v; } ),
350 new ParameterDefn<float>("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
351 32f,
352 (s) => { return MeshMegaPrimLOD; },
353 (s,v) => { MeshMegaPrimLOD = v; } ),
354 new ParameterDefn<float>("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
355 32f,
356 (s) => { return SculptLOD; },
357 (s,v) => { SculptLOD = v; } ),
358
359 new ParameterDefn<int>("MaxSubStep", "In simulation step, maximum number of substeps",
360 10,
361 (s) => { return s.m_maxSubSteps; },
362 (s,v) => { s.m_maxSubSteps = (int)v; } ),
363 new ParameterDefn<float>("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
364 1f / 60f,
365 (s) => { return s.m_fixedTimeStep; },
366 (s,v) => { s.m_fixedTimeStep = v; } ),
367 new ParameterDefn<float>("NominalFrameRate", "The base frame rate we claim",
368 55f,
369 (s) => { return s.NominalFrameRate; },
370 (s,v) => { s.NominalFrameRate = (int)v; } ),
371 new ParameterDefn<int>("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
372 2048,
373 (s) => { return s.m_maxCollisionsPerFrame; },
374 (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
375 new ParameterDefn<int>("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
376 8000,
377 (s) => { return s.m_maxUpdatesPerFrame; },
378 (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
379
380 new ParameterDefn<float>("MinObjectMass", "Minimum object mass (0.0001)",
381 0.0001f,
382 (s) => { return MinimumObjectMass; },
383 (s,v) => { MinimumObjectMass = v; } ),
384 new ParameterDefn<float>("MaxObjectMass", "Maximum object mass (10000.01)",
385 10000.01f,
386 (s) => { return MaximumObjectMass; },
387 (s,v) => { MaximumObjectMass = v; } ),
388 new ParameterDefn<float>("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
389 1000.0f,
390 (s) => { return MaxLinearVelocity; },
391 (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ),
392 new ParameterDefn<float>("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
393 1000.0f,
394 (s) => { return MaxAngularVelocity; },
395 (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ),
396 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
397 new ParameterDefn<float>("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
398 20000.0f,
399 (s) => { return MaxAddForceMagnitude; },
400 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
401 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
402 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
403 0.01f,
404 (s) => { return DensityScaleFactor; },
405 (s,v) => { DensityScaleFactor = v; } ),
406
407 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
408 2200f,
409 (s) => { return (float)PID_D; },
410 (s,v) => { PID_D = v; } ),
411 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing",
412 900f,
413 (s) => { return (float)PID_P; },
414 (s,v) => { PID_P = v; } ),
415
416 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects",
417 0.2f,
418 (s) => { return DefaultFriction; },
419 (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ),
420 new ParameterDefn<float>("DefaultDensity", "Density for new objects" ,
421 10.000006836f, // Aluminum g/cm3
422 (s) => { return DefaultDensity; },
423 (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ),
424 new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" ,
425 0f,
426 (s) => { return DefaultRestitution; },
427 (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ),
428 new ParameterDefn<float>("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
429 0.04f,
430 (s) => { return CollisionMargin; },
431 (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ),
432 new ParameterDefn<float>("Gravity", "Vertical force of gravity (negative means down)",
433 -9.80665f,
434 (s) => { return Gravity; },
435 (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; },
436 (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ),
437
438
439 new ParameterDefn<float>("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
440 0f,
441 (s) => { return LinearDamping; },
442 (s,v) => { LinearDamping = v; },
443 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
444 new ParameterDefn<float>("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
445 0f,
446 (s) => { return AngularDamping; },
447 (s,v) => { AngularDamping = v; },
448 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
449 new ParameterDefn<float>("DeactivationTime", "Seconds before considering an object potentially static",
450 0.2f,
451 (s) => { return DeactivationTime; },
452 (s,v) => { DeactivationTime = v; },
453 (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ),
454 new ParameterDefn<float>("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
455 0.8f,
456 (s) => { return LinearSleepingThreshold; },
457 (s,v) => { LinearSleepingThreshold = v;},
458 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
459 new ParameterDefn<float>("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
460 1.0f,
461 (s) => { return AngularSleepingThreshold; },
462 (s,v) => { AngularSleepingThreshold = v;},
463 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
464 new ParameterDefn<float>("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
465 0.0f, // set to zero to disable
466 (s) => { return CcdMotionThreshold; },
467 (s,v) => { CcdMotionThreshold = v;},
468 (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ),
469 new ParameterDefn<float>("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
470 0.2f,
471 (s) => { return CcdSweptSphereRadius; },
472 (s,v) => { CcdSweptSphereRadius = v;},
473 (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ),
474 new ParameterDefn<float>("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" ,
475 0.0f,
476 (s) => { return ContactProcessingThreshold; },
477 (s,v) => { ContactProcessingThreshold = v;},
478 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
479
480 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
481 (float)BSTerrainPhys.TerrainImplementation.Mesh,
482 (s) => { return TerrainImplementation; },
483 (s,v) => { TerrainImplementation = v; } ),
484 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
485 2,
486 (s) => { return TerrainMeshMagnification; },
487 (s,v) => { TerrainMeshMagnification = v; } ),
488 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
489 0.3f,
490 (s) => { return TerrainFriction; },
491 (s,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
492 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" ,
493 0.8f,
494 (s) => { return TerrainHitFraction; },
495 (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
496 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" ,
497 0f,
498 (s) => { return TerrainRestitution; },
499 (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
500 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
501 0.0f,
502 (s) => { return TerrainContactProcessingThreshold; },
503 (s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ),
504 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
505 0.08f,
506 (s) => { return TerrainCollisionMargin; },
507 (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
508
509 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
510 0.2f,
511 (s) => { return AvatarFriction; },
512 (s,v) => { AvatarFriction = v; } ),
513 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
514 0.95f,
515 (s) => { return AvatarStandingFriction; },
516 (s,v) => { AvatarStandingFriction = v; } ),
517 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
518 1.3f,
519 (s) => { return AvatarAlwaysRunFactor; },
520 (s,v) => { AvatarAlwaysRunFactor = v; } ),
521 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
522 3.5f,
523 (s) => { return AvatarDensity; },
524 (s,v) => { AvatarDensity = v; } ),
525 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
526 0f,
527 (s) => { return AvatarRestitution; },
528 (s,v) => { AvatarRestitution = v; } ),
529 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
530 0.6f,
531 (s) => { return AvatarCapsuleWidth; },
532 (s,v) => { AvatarCapsuleWidth = v; } ),
533 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
534 0.45f,
535 (s) => { return AvatarCapsuleDepth; },
536 (s,v) => { AvatarCapsuleDepth = v; } ),
537 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar",
538 1.5f,
539 (s) => { return AvatarCapsuleHeight; },
540 (s,v) => { AvatarCapsuleHeight = v; } ),
541 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
542 0.1f,
543 (s) => { return AvatarContactProcessingThreshold; },
544 (s,v) => { AvatarContactProcessingThreshold = v; } ),
545 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
546 1.0f,
547 (s) => { return AvatarBelowGroundUpCorrectionMeters; },
548 (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ),
549 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
550 0.3f,
551 (s) => { return AvatarStepHeight; },
552 (s,v) => { AvatarStepHeight = v; } ),
553 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
554 0.6f,
555 (s) => { return AvatarStepApproachFactor; },
556 (s,v) => { AvatarStepApproachFactor = v; } ),
557 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
558 2.0f,
559 (s) => { return AvatarStepForceFactor; },
560 (s,v) => { AvatarStepForceFactor = v; } ),
561
562 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
563 1000.0f,
564 (s) => { return (float)VehicleMaxLinearVelocity; },
565 (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ),
566 new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
567 12.0f,
568 (s) => { return (float)VehicleMaxAngularVelocity; },
569 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ),
570 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
571 0.0f,
572 (s) => { return VehicleAngularDamping; },
573 (s,v) => { VehicleAngularDamping = v; } ),
574 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)",
575 new Vector3(1f, 1f, 1f),
576 (s) => { return VehicleLinearFactor; },
577 (s,v) => { VehicleLinearFactor = v; } ),
578 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)",
579 new Vector3(1f, 1f, 1f),
580 (s) => { return VehicleAngularFactor; },
581 (s,v) => { VehicleAngularFactor = v; } ),
582 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)",
583 0.0f,
584 (s) => { return VehicleFriction; },
585 (s,v) => { VehicleFriction = v; } ),
586 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
587 0.0f,
588 (s) => { return VehicleRestitution; },
589 (s,v) => { VehicleRestitution = v; } ),
590 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
591 0.2f,
592 (s) => { return VehicleGroundGravityFudge; },
593 (s,v) => { VehicleGroundGravityFudge = v; } ),
594 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
595 60.0f,
596 (s) => { return VehicleAngularBankingTimescaleFudge; },
597 (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ),
598 new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
599 false,
600 (s) => { return VehicleDebuggingEnabled; },
601 (s,v) => { VehicleDebuggingEnabled = v; } ),
602
603 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
604 0f,
605 (s) => { return MaxPersistantManifoldPoolSize; },
606 (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
607 new ParameterDefn<float>("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
608 0f,
609 (s) => { return MaxCollisionAlgorithmPoolSize; },
610 (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
611 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
612 false,
613 (s) => { return ShouldDisableContactPoolDynamicAllocation; },
614 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
615 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
616 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
617 false,
618 (s) => { return ShouldForceUpdateAllAabbs; },
619 (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ),
620 new ParameterDefn<bool>("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
621 true,
622 (s) => { return ShouldRandomizeSolverOrder; },
623 (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ),
624 new ParameterDefn<bool>("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
625 true,
626 (s) => { return ShouldSplitSimulationIslands; },
627 (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ),
628 new ParameterDefn<bool>("ShouldEnableFrictionCaching", "Enable friction computation caching",
629 true,
630 (s) => { return ShouldEnableFrictionCaching; },
631 (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ),
632 new ParameterDefn<float>("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
633 0f, // zero says use Bullet default
634 (s) => { return NumberOfSolverIterations; },
635 (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
636 new ParameterDefn<bool>("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.",
637 true,
638 (s) => { return UseSingleSidedMeshes; },
639 (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ),
640 new ParameterDefn<float>("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))",
641 0f,
642 (s) => { return GlobalContactBreakingThreshold; },
643 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
644
645 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
646 7,
647 (s) => { return CSHullMaxDepthSplit; },
648 (s,v) => { CSHullMaxDepthSplit = v; } ),
649 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
650 2,
651 (s) => { return CSHullMaxDepthSplitForSimpleShapes; },
652 (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ),
653 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
654 5f,
655 (s) => { return CSHullConcavityThresholdPercent; },
656 (s,v) => { CSHullConcavityThresholdPercent = v; } ),
657 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
658 5f,
659 (s) => { return CSHullVolumeConservationThresholdPercent; },
660 (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ),
661 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
662 32,
663 (s) => { return CSHullMaxVertices; },
664 (s,v) => { CSHullMaxVertices = v; } ),
665 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
666 0,
667 (s) => { return CSHullMaxSkinWidth; },
668 (s,v) => { CSHullMaxSkinWidth = v; } ),
669
670 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
671 (float)BSLinkset.LinksetImplementation.Compound,
672 (s) => { return LinksetImplementation; },
673 (s,v) => { LinksetImplementation = v; } ),
674 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
675 false,
676 (s) => { return LinkConstraintUseFrameOffset; },
677 (s,v) => { LinkConstraintUseFrameOffset = v; } ),
678 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
679 true,
680 (s) => { return LinkConstraintEnableTransMotor; },
681 (s,v) => { LinkConstraintEnableTransMotor = v; } ),
682 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
683 5.0f,
684 (s) => { return LinkConstraintTransMotorMaxVel; },
685 (s,v) => { LinkConstraintTransMotorMaxVel = v; } ),
686 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
687 0.1f,
688 (s) => { return LinkConstraintTransMotorMaxForce; },
689 (s,v) => { LinkConstraintTransMotorMaxForce = v; } ),
690 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
691 0.1f,
692 (s) => { return LinkConstraintCFM; },
693 (s,v) => { LinkConstraintCFM = v; } ),
694 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
695 0.1f,
696 (s) => { return LinkConstraintERP; },
697 (s,v) => { LinkConstraintERP = v; } ),
698 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
699 40,
700 (s) => { return LinkConstraintSolverIterations; },
701 (s,v) => { LinkConstraintSolverIterations = v; } ),
702
703 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
704 0,
705 (s) => { return s.PhysicsMetricDumpFrames; },
706 (s,v) => { s.PhysicsMetricDumpFrames = v; } ),
707 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
708 0f,
709 (s) => { return 0f; },
710 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ),
711 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
712 0f,
713 (s) => { return 0f; },
714 (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
715 };
716
717 // Convert a boolean to our numeric true and false values
718 public static float NumericBool(bool b)
719 {
720 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
721 }
722
723 // Convert numeric true and false values to a boolean
724 public static bool BoolNumeric(float b)
725 {
726 return (b == ConfigurationParameters.numericTrue ? true : false);
727 }
728
729 // Search through the parameter definitions and return the matching
730 // ParameterDefn structure.
731 // Case does not matter as names are compared after converting to lower case.
732 // Returns 'false' if the parameter is not found.
733 internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn)
734 {
735 bool ret = false;
736 ParameterDefnBase foundDefn = null;
737 string pName = paramName.ToLower();
738
739 foreach (ParameterDefnBase parm in ParameterDefinitions)
740 {
741 if (pName == parm.name.ToLower())
742 {
743 foundDefn = parm;
744 ret = true;
745 break;
746 }
747 }
748 defn = foundDefn;
749 return ret;
750 }
751
752 // Pass through the settable parameters and set the default values
753 internal static void SetParameterDefaultValues(BSScene physicsScene)
754 {
755 foreach (ParameterDefnBase parm in ParameterDefinitions)
756 {
757 parm.AssignDefault(physicsScene);
758 }
759 }
760
761 // Get user set values out of the ini file.
762 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
763 {
764 foreach (ParameterDefnBase parm in ParameterDefinitions)
765 {
766 parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene)));
767 }
768 }
769
770 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
771
772 // This creates an array in the correct format for returning the list of
773 // parameters. This is used by the 'list' option of the 'physics' command.
774 internal static void BuildParameterTable()
775 {
776 if (SettableParameters.Length < ParameterDefinitions.Length)
777 {
778 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
779 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
780 {
781 ParameterDefnBase pd = ParameterDefinitions[ii];
782 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
783 }
784
785 // make the list alphabetical for ease of finding anything
786 entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); });
787
788 SettableParameters = entries.ToArray();
789 }
790 }
791
792 // =====================================================================
793 // =====================================================================
794 // There are parameters that, when set, cause things to happen in the physics engine.
795 // This causes the broadphase collision cache to be cleared.
796 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v)
797 {
798 BSScene physScene = pPhysScene;
799 physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate()
800 {
801 physScene.PE.ResetBroadphasePool(physScene.World);
802 });
803 }
804
805 // This causes the constraint solver cache to be cleared and reset.
806 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
807 {
808 BSScene physScene = pPhysScene;
809 physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate()
810 {
811 physScene.PE.ResetConstraintSolver(physScene.World);
812 });
813 }
814}
815}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..6bb88c7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -45,6 +45,26 @@ 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
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
59public enum UpdatedProperties : uint
60{
61 Position = 1 << 0,
62 Orientation = 1 << 1,
63 Velocity = 1 << 2,
64 Acceleration = 1 << 3,
65 RotationalVelocity = 1 << 4,
66 EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity,
67}
48public abstract class BSPhysObject : PhysicsActor 68public abstract class BSPhysObject : PhysicsActor
49{ 69{
50 protected BSPhysObject() 70 protected BSPhysObject()
@@ -55,15 +75,40 @@ public abstract class BSPhysObject : PhysicsActor
55 PhysicsScene = parentScene; 75 PhysicsScene = parentScene;
56 LocalID = localID; 76 LocalID = localID;
57 PhysObjectName = name; 77 PhysObjectName = name;
78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
58 TypeName = typeName; 79 TypeName = typeName;
59 80
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 81 // Initialize variables kept in base.
61 LastAssetBuildFailed = false; 82 GravModifier = 1.0f;
83 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
84
85 // We don't have any physical representation yet.
86 PhysBody = new BulletBody(localID);
87 PhysShape = new BulletShape();
88
89 PrimAssetState = PrimAssetCondition.Unknown;
90
91 // Default material type. Also sets Friction, Restitution and Density.
92 SetMaterial((int)MaterialAttributes.Material.Wood);
62 93
63 CollisionCollection = new CollisionEventUpdate(); 94 CollisionCollection = new CollisionEventUpdate();
95 CollisionsLastTick = CollisionCollection;
64 SubscribedEventsMs = 0; 96 SubscribedEventsMs = 0;
65 CollidingStep = 0; 97 CollidingStep = 0;
66 CollidingGroundStep = 0; 98 CollidingGroundStep = 0;
99 CollisionAccumulation = 0;
100 ColliderIsMoving = false;
101 CollisionScore = 0;
102
103 // All axis free.
104 LockedAxis = LockedAxisFree;
105 }
106
107 // Tell the object to clean up.
108 public virtual void Destroy()
109 {
110 UnRegisterAllPreStepActions();
111 UnRegisterAllPostStepActions();
67 } 112 }
68 113
69 public BSScene PhysicsScene { get; protected set; } 114 public BSScene PhysicsScene { get; protected set; }
@@ -71,13 +116,15 @@ public abstract class BSPhysObject : PhysicsActor
71 public string PhysObjectName { get; protected set; } 116 public string PhysObjectName { get; protected set; }
72 public string TypeName { get; protected set; } 117 public string TypeName { get; protected set; }
73 118
74 public BSLinkset Linkset { get; set; }
75 119
76 // Return the object mass without calculating it or having side effects 120 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 121 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...) 122 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass); 123 // 'inWorld' true if the object has already been added to the dynamic world.
124 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
80 125
126 // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
127 public virtual OMV.Vector3 Gravity { get; set; }
81 // The last value calculated for the prim's inertia 128 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; } 129 public OMV.Vector3 Inertia { get; set; }
83 130
@@ -86,12 +133,17 @@ public abstract class BSPhysObject : PhysicsActor
86 // Reference to the physical shape (btCollisionShape) of this object 133 // Reference to the physical shape (btCollisionShape) of this object
87 public BulletShape PhysShape; 134 public BulletShape PhysShape;
88 135
89 // 'true' if the mesh's underlying asset failed to build. 136 // The physical representation of the prim might require an asset fetch.
90 // This will keep us from looping after the first time the build failed. 137 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
91 public bool LastAssetBuildFailed { get; set; } 138 public enum PrimAssetCondition
139 {
140 Unknown, Waiting, Failed, Fetched
141 }
142 public PrimAssetCondition PrimAssetState { get; set; }
92 143
93 // The objects base shape information. Null if not a prim type shape. 144 // The objects base shape information. Null if not a prim type shape.
94 public PrimitiveBaseShape BaseShape { get; protected set; } 145 public PrimitiveBaseShape BaseShape { get; protected set; }
146
95 // Some types of objects have preferred physical representations. 147 // Some types of objects have preferred physical representations.
96 // Returns SHAPE_UNKNOWN if there is no preference. 148 // Returns SHAPE_UNKNOWN if there is no preference.
97 public virtual BSPhysicsShapeType PreferredPhysicalShape 149 public virtual BSPhysicsShapeType PreferredPhysicalShape
@@ -105,29 +157,46 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 157 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 158 public EntityProperties LastEntityProperties { get; set; }
107 159
108 public abstract OMV.Vector3 Scale { get; set; } 160 public virtual OMV.Vector3 Scale { get; set; }
161
162 // It can be confusing for an actor to know if it should move or update an object
163 // depeneding on the setting of 'selected', 'physical, ...
164 // This flag is the true test -- if true, the object is being acted on in the physical world
165 public abstract bool IsPhysicallyActive { get; }
166
167 // Detailed state of the object.
109 public abstract bool IsSolid { get; } 168 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 169 public abstract bool IsStatic { get; }
170 public abstract bool IsSelected { get; }
171
172 // Materialness
173 public MaterialAttributes.Material Material { get; private set; }
174 public override void SetMaterial(int material)
175 {
176 Material = (MaterialAttributes.Material)material;
177
178 // Setting the material sets the material attributes also.
179 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
180 Friction = matAttrib.friction;
181 Restitution = matAttrib.restitution;
182 Density = matAttrib.density / BSParam.DensityScaleFactor;
183 DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
184 }
111 185
112 // Stop all physical motion. 186 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 187 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime); 188 public abstract void ZeroAngularMotion(bool inTaintTime);
115 189
116 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
117 public virtual void StepVehicle(float timeStep) { }
118
119 // Update the physical location and motion of the object. Called with data from Bullet. 190 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop); 191 public abstract void UpdateProperties(EntityProperties entprop);
121 192
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; } 193 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; } 194 public abstract OMV.Vector3 ForcePosition { get; set; }
127 195
128 public abstract OMV.Quaternion RawOrientation { get; set; } 196 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 197 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 198
199 public abstract OMV.Vector3 RawVelocity { get; set; }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 200 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 201
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 202 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -136,6 +205,32 @@ public abstract class BSPhysObject : PhysicsActor
136 205
137 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 206 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
138 207
208 // The current velocity forward
209 public virtual float ForwardSpeed
210 {
211 get
212 {
213 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
214 return characterOrientedVelocity.X;
215 }
216 }
217 // The forward speed we are trying to achieve (TargetVelocity)
218 public virtual float TargetVelocitySpeed
219 {
220 get
221 {
222 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
223 return characterOrientedVelocity.X;
224 }
225 }
226
227 // The user can optionally set the center of mass. The user's setting will override any
228 // computed center-of-mass (like in linksets).
229 public OMV.Vector3? UserSetCenterOfMass { get; set; }
230
231 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
232 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
233
139 #region Collisions 234 #region Collisions
140 235
141 // Requested number of milliseconds between collision events. Zero means disabled. 236 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -146,38 +241,82 @@ public abstract class BSPhysObject : PhysicsActor
146 protected long CollidingStep { get; set; } 241 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground 242 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; } 243 protected long CollidingGroundStep { get; set; }
244 // The simulation step that last collided with an object
245 protected long CollidingObjectStep { get; set; }
149 // The collision flags we think are set in Bullet 246 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; } 247 protected CollisionFlags CurrentCollisionFlags { get; set; }
248 // On a collision, check the collider and remember if the last collider was moving
249 // Used to modify the standing of avatars (avatars on stationary things stand still)
250 protected bool ColliderIsMoving;
251
252 // Count of collisions for this object
253 protected long CollisionAccumulation { get; set; }
254
255 public override bool IsColliding {
256 get { return (CollidingStep == PhysicsScene.SimulationStep); }
257 set {
258 if (value)
259 CollidingStep = PhysicsScene.SimulationStep;
260 else
261 CollidingStep = 0;
262 }
263 }
264 public override bool CollidingGround {
265 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
266 set
267 {
268 if (value)
269 CollidingGroundStep = PhysicsScene.SimulationStep;
270 else
271 CollidingGroundStep = 0;
272 }
273 }
274 public override bool CollidingObj {
275 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
276 set {
277 if (value)
278 CollidingObjectStep = PhysicsScene.SimulationStep;
279 else
280 CollidingObjectStep = 0;
281 }
282 }
151 283
152 // The collisions that have been collected this tick 284 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection; 285 protected CollisionEventUpdate CollisionCollection;
286 // Remember collisions from last tick for fancy collision based actions
287 // (like a BSCharacter walking up stairs).
288 protected CollisionEventUpdate CollisionsLastTick;
154 289
155 // The simulation step is telling this object about a collision. 290 // The simulation step is telling this object about a collision.
156 // Return 'true' if a collision was processed and should be sent up. 291 // Return 'true' if a collision was processed and should be sent up.
292 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
157 // Called at taint time from within the Step() function 293 // Called at taint time from within the Step() function
158 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 294 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
159 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 295 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
160 { 296 {
161 bool ret = false; 297 bool ret = false;
162 298
163 // The following lines make IsColliding() and IsCollidingGround() work 299 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
164 CollidingStep = PhysicsScene.SimulationStep; 300 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 301 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 { 302 {
167 CollidingGroundStep = PhysicsScene.SimulationStep; 303 CollidingGroundStep = PhysicsScene.SimulationStep;
168 } 304 }
169 305 else
170 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
172 { 306 {
173 return ret; 307 CollidingObjectStep = PhysicsScene.SimulationStep;
174 } 308 }
175 309
176 // if someone has subscribed for collision events.... 310 CollisionAccumulation++;
311
312 // For movement tests, remember if we are colliding with an object that is moving.
313 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
314
315 // If someone has subscribed for collision events log the collision so it will be reported up
177 if (SubscribedEvents()) { 316 if (SubscribedEvents()) {
178 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 317 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
179 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", 318 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
180 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); 319 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
181 320
182 ret = true; 321 ret = true;
183 } 322 }
@@ -191,8 +330,9 @@ public abstract class BSPhysObject : PhysicsActor
191 public virtual bool SendCollisions() 330 public virtual bool SendCollisions()
192 { 331 {
193 bool ret = true; 332 bool ret = true;
333
194 // If the 'no collision' call, force it to happen right now so quick collision_end 334 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 335 bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0);
196 336
197 // throttle the collisions to the number of milliseconds specified in the subscription 337 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 338 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -207,11 +347,16 @@ public abstract class BSPhysObject : PhysicsActor
207 ret = false; 347 ret = false;
208 } 348 }
209 349
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 350 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 351 base.SendCollisionUpdate(CollisionCollection);
212 352
213 // The collisionCollection structure is passed around in the simulator. 353 // Remember the collisions from this tick for some collision specific processing.
354 CollisionsLastTick = CollisionCollection;
355
356 // 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. 357 // Make sure we don't have a handle to that one and that a new one is used for next time.
358 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
359 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 360 CollisionCollection = new CollisionEventUpdate();
216 } 361 }
217 return ret; 362 return ret;
@@ -229,7 +374,8 @@ public abstract class BSPhysObject : PhysicsActor
229 374
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 375 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 376 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 377 if (PhysBody.HasPhysicalBody)
378 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 379 });
234 } 380 }
235 else 381 else
@@ -243,21 +389,187 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 389 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 390 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 391 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 392 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
393 if (PhysBody.HasPhysicalBody)
394 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 395 });
248 } 396 }
249 // Return 'true' if the simulator wants collision events 397 // Return 'true' if the simulator wants collision events
250 public override bool SubscribedEvents() { 398 public override bool SubscribedEvents() {
251 return (SubscribedEventsMs > 0); 399 return (SubscribedEventsMs > 0);
252 } 400 }
401 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
402 // each time called. So this is built to be light weight for each collision and to do
403 // all the processing when the user asks for the info.
404 public void ComputeCollisionScore()
405 {
406 // Scale the collision count by the time since the last collision.
407 // The "+1" prevents dividing by zero.
408 long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1;
409 CollisionScore = CollisionAccumulation / timeAgo;
410 }
411 public override float CollisionScore { get; set; }
253 412
254 #endregion // Collisions 413 #endregion // Collisions
255 414
415 #region Per Simulation Step actions
416 // There are some actions that must be performed for a physical object before each simulation step.
417 // These actions are optional so, rather than scanning all the physical objects and asking them
418 // if they have anything to do, a physical object registers for an event call before the step is performed.
419 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
420 private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
421 private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
422 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
423 {
424 string identifier = op + "-" + id.ToString();
425
426 lock (RegisteredPrestepActions)
427 {
428 // Clean out any existing action
429 UnRegisterPreStepAction(op, id);
430 RegisteredPrestepActions[identifier] = actn;
431 PhysicsScene.BeforeStep += actn;
432 }
433 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
434 }
435
436 // Unregister a pre step action. Safe to call if the action has not been registered.
437 // Returns 'true' if an action was actually removed
438 protected bool UnRegisterPreStepAction(string op, uint id)
439 {
440 string identifier = op + "-" + id.ToString();
441 bool removed = false;
442 lock (RegisteredPrestepActions)
443 {
444 if (RegisteredPrestepActions.ContainsKey(identifier))
445 {
446 PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
447 RegisteredPrestepActions.Remove(identifier);
448 removed = true;
449 }
450 }
451 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
452 return removed;
453 }
454
455 protected void UnRegisterAllPreStepActions()
456 {
457 lock (RegisteredPrestepActions)
458 {
459 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
460 {
461 PhysicsScene.BeforeStep -= kvp.Value;
462 }
463 RegisteredPrestepActions.Clear();
464 }
465 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
466 }
467
468 protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
469 {
470 string identifier = op + "-" + id.ToString();
471
472 lock (RegisteredPoststepActions)
473 {
474 // Clean out any existing action
475 UnRegisterPostStepAction(op, id);
476 RegisteredPoststepActions[identifier] = actn;
477 PhysicsScene.AfterStep += actn;
478 }
479 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
480 }
481
482 // Unregister a pre step action. Safe to call if the action has not been registered.
483 // Returns 'true' if an action was actually removed.
484 protected bool UnRegisterPostStepAction(string op, uint id)
485 {
486 string identifier = op + "-" + id.ToString();
487 bool removed = false;
488 lock (RegisteredPoststepActions)
489 {
490 if (RegisteredPoststepActions.ContainsKey(identifier))
491 {
492 PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
493 RegisteredPoststepActions.Remove(identifier);
494 removed = true;
495 }
496 }
497 DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
498 return removed;
499 }
500
501 protected void UnRegisterAllPostStepActions()
502 {
503 lock (RegisteredPoststepActions)
504 {
505 foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
506 {
507 PhysicsScene.AfterStep -= kvp.Value;
508 }
509 RegisteredPoststepActions.Clear();
510 }
511 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
512 }
513
514 // When an update to the physical properties happens, this event is fired to let
515 // different actors to modify the update before it is passed around
516 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
517 public event PreUpdatePropertyAction OnPreUpdateProperty;
518 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
519 {
520 PreUpdatePropertyAction actions = OnPreUpdateProperty;
521 if (actions != null)
522 actions(ref entprop);
523 }
524
525 private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
526 public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
527 {
528 lock (RegisteredPreUpdatePropertyActions)
529 {
530 // Clean out any existing action
531 UnRegisterPreUpdatePropertyAction(identifier);
532 RegisteredPreUpdatePropertyActions[identifier] = actn;
533 OnPreUpdateProperty += actn;
534 }
535 DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
536 }
537 public bool UnRegisterPreUpdatePropertyAction(string identifier)
538 {
539 bool removed = false;
540 lock (RegisteredPreUpdatePropertyActions)
541 {
542 if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
543 {
544 OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
545 RegisteredPreUpdatePropertyActions.Remove(identifier);
546 removed = true;
547 }
548 }
549 DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
550 return removed;
551 }
552 public void UnRegisterAllPreUpdatePropertyActions()
553 {
554 lock (RegisteredPreUpdatePropertyActions)
555 {
556 foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
557 {
558 OnPreUpdateProperty -= kvp.Value;
559 }
560 RegisteredPreUpdatePropertyActions.Clear();
561 }
562 DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
563 }
564
565 #endregion // Per Simulation Step actions
566
256 // High performance detailed logging routine used by the physical objects. 567 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args) 568 protected void DetailLog(string msg, params Object[] args)
258 { 569 {
259 if (PhysicsScene.PhysicsLogging.Enabled) 570 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args); 571 PhysicsScene.DetailLog(msg, args);
261 } 572 }
573
262} 574}
263} 575}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
index 20f5180..9442854 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -59,13 +59,7 @@ public class BSPlugin : IPhysicsPlugin
59 { 59 {
60 if (_mScene == null) 60 if (_mScene == null)
61 { 61 {
62 if (Util.IsWindows()) 62 _mScene = new BSScene(GetName(), sceneIdentifier);
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);
69 } 63 }
70 return (_mScene); 64 return (_mScene);
71 } 65 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2b3fa25..6a5461a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -39,51 +39,49 @@ namespace OpenSim.Region.Physics.BulletSPlugin
39{ 39{
40 40
41 [Serializable] 41 [Serializable]
42public sealed class BSPrim : BSPhysObject 42public class BSPrim : BSPhysObject
43{ 43{
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
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;
52 private bool _isSelected; 51 private bool _isSelected;
53 private bool _isVolumeDetect; 52 private bool _isVolumeDetect;
53
54 // _position is what the simulator thinks the positions of the prim is.
54 private OMV.Vector3 _position; 55 private OMV.Vector3 _position;
56
55 private float _mass; // the mass of this object 57 private float _mass; // the mass of this object
56 private float _density;
57 private OMV.Vector3 _force; 58 private OMV.Vector3 _force;
58 private OMV.Vector3 _velocity; 59 private OMV.Vector3 _velocity;
59 private OMV.Vector3 _torque; 60 private OMV.Vector3 _torque;
60 private float _collisionScore;
61 private OMV.Vector3 _acceleration; 61 private OMV.Vector3 _acceleration;
62 private OMV.Quaternion _orientation; 62 private OMV.Quaternion _orientation;
63 private int _physicsActorType; 63 private int _physicsActorType;
64 private bool _isPhysical; 64 private bool _isPhysical;
65 private bool _flying; 65 private bool _flying;
66 private float _friction;
67 private float _restitution;
68 private bool _setAlwaysRun; 66 private bool _setAlwaysRun;
69 private bool _throttleUpdates; 67 private bool _throttleUpdates;
70 private bool _isColliding;
71 private bool _collidingGround;
72 private bool _collidingObj;
73 private bool _floatOnWater; 68 private bool _floatOnWater;
74 private OMV.Vector3 _rotationalVelocity; 69 private OMV.Vector3 _rotationalVelocity;
75 private bool _kinematic; 70 private bool _kinematic;
76 private float _buoyancy; 71 private float _buoyancy;
77 72
78 private BSDynamics _vehicle; 73 private int CrossingFailures { get; set; }
79 74
75 public BSDynamics VehicleController { get; private set; }
76
77 private BSVMotor _targetMotor;
80 private OMV.Vector3 _PIDTarget; 78 private OMV.Vector3 _PIDTarget;
81 private bool _usePID;
82 private float _PIDTau; 79 private float _PIDTau;
83 private bool _useHoverPID; 80
81 private BSFMotor _hoverMotor;
84 private float _PIDHoverHeight; 82 private float _PIDHoverHeight;
85 private PIDHoverType _PIDHoverType; 83 private PIDHoverType _PIDHoverType;
86 private float _PIDHoverTao; 84 private float _PIDHoverTau;
87 85
88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 86 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 87 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -93,31 +91,29 @@ public sealed class BSPrim : BSPhysObject
93 _physicsActorType = (int)ActorTypes.Prim; 91 _physicsActorType = (int)ActorTypes.Prim;
94 _position = pos; 92 _position = pos;
95 _size = size; 93 _size = size;
96 Scale = size; // the scale will be set by CreateGeom depending on object type 94 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
97 _orientation = rotation; 95 _orientation = rotation;
98 _buoyancy = 1f; 96 _buoyancy = 0f;
99 _velocity = OMV.Vector3.Zero; 97 _velocity = OMV.Vector3.Zero;
100 _rotationalVelocity = OMV.Vector3.Zero; 98 _rotationalVelocity = OMV.Vector3.Zero;
101 BaseShape = pbs; 99 BaseShape = pbs;
102 _isPhysical = pisPhysical; 100 _isPhysical = pisPhysical;
103 _isVolumeDetect = false; 101 _isVolumeDetect = false;
104 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
105 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
106 _restitution = PhysicsScene.Params.defaultRestitution;
107 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
108 _mass = CalculateMass();
109 102
110 // No body or shape yet 103 VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero); 104
112 PhysShape = new BulletShape(IntPtr.Zero); 105 _mass = CalculateMass();
113 106
114 DetailLog("{0},BSPrim.constructor,call", LocalID); 107 DetailLog("{0},BSPrim.constructor,call", LocalID);
115 // do the actual object creation at taint time 108 // do the actual object creation at taint time
116 PhysicsScene.TaintedObject("BSPrim.create", delegate() 109 PhysicsScene.TaintedObject("BSPrim.create", delegate()
117 { 110 {
111 // Make sure the object is being created with some sanity.
112 ExtremeSanityCheck(true /* inTaintTime */);
113
118 CreateGeomAndObject(true); 114 CreateGeomAndObject(true);
119 115
120 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); 116 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody);
121 }); 117 });
122 } 118 }
123 119
@@ -125,15 +121,7 @@ public sealed class BSPrim : BSPhysObject
125 public override void Destroy() 121 public override void Destroy()
126 { 122 {
127 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 123 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
128 124 base.Destroy();
129 // Undo any links between me and any other object
130 BSPhysObject parentBefore = Linkset.LinksetRoot;
131 int childrenBefore = Linkset.NumberOfChildren;
132
133 Linkset = Linkset.RemoveMeFromLinkset(this);
134
135 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
136 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
137 125
138 // Undo any vehicle properties 126 // Undo any vehicle properties
139 this.VehicleType = (int)Vehicle.TYPE_NONE; 127 this.VehicleType = (int)Vehicle.TYPE_NONE;
@@ -142,8 +130,10 @@ public sealed class BSPrim : BSPhysObject
142 { 130 {
143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 131 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
144 // If there are physical body and shape, release my use of same. 132 // If there are physical body and shape, release my use of same.
145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 133 PhysicsScene.Shapes.DereferenceBody(PhysBody, null);
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 134 PhysBody.Clear();
135 PhysicsScene.Shapes.DereferenceShape(PhysShape, null);
136 PhysShape.Clear();
147 }); 137 });
148 } 138 }
149 139
@@ -157,31 +147,37 @@ public sealed class BSPrim : BSPhysObject
157 // We presume the scale and size are the same. If scale must be changed for 147 // 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. 148 // the physical shape, that is done when the geometry is built.
159 _size = value; 149 _size = value;
150 Scale = _size;
160 ForceBodyShapeRebuild(false); 151 ForceBodyShapeRebuild(false);
161 } 152 }
162 } 153 }
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 154
167 public override PrimitiveBaseShape Shape { 155 public override PrimitiveBaseShape Shape {
168 set { 156 set {
169 BaseShape = value; 157 BaseShape = value;
158 PrimAssetState = PrimAssetCondition.Unknown;
170 ForceBodyShapeRebuild(false); 159 ForceBodyShapeRebuild(false);
171 } 160 }
172 } 161 }
173 // Whatever the linkset wants is what I want. 162 // 'unknown' says to choose the best type
174 public override BSPhysicsShapeType PreferredPhysicalShape 163 public override BSPhysicsShapeType PreferredPhysicalShape
175 { get { return Linkset.PreferredPhysicalShape(this); } } 164 { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } }
176 165
177 public override bool ForceBodyShapeRebuild(bool inTaintTime) 166 public override bool ForceBodyShapeRebuild(bool inTaintTime)
178 { 167 {
179 LastAssetBuildFailed = false; 168 if (inTaintTime)
180 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
181 { 169 {
182 _mass = CalculateMass(); // changing the shape changes the mass 170 _mass = CalculateMass(); // changing the shape changes the mass
183 CreateGeomAndObject(true); 171 CreateGeomAndObject(true);
184 }); 172 }
173 else
174 {
175 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate()
176 {
177 _mass = CalculateMass(); // changing the shape changes the mass
178 CreateGeomAndObject(true);
179 });
180 }
185 return true; 181 return true;
186 } 182 }
187 public override bool Grabbed { 183 public override bool Grabbed {
@@ -189,46 +185,44 @@ public sealed class BSPrim : BSPhysObject
189 } 185 }
190 } 186 }
191 public override bool Selected { 187 public override bool Selected {
192 set { 188 set
193 _isSelected = value; 189 {
194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 190 if (value != _isSelected)
195 { 191 {
196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 192 _isSelected = value;
197 SetObjectDynamic(false); 193 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 }); 194 {
195 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
196 SetObjectDynamic(false);
197 });
198 }
199 } 199 }
200 } 200 }
201 public override void CrossingFailure() { return; } 201 public override bool IsSelected
202 {
203 get { return _isSelected; }
204 }
202 205
203 // link me to the specified parent 206 public override void CrossingFailure()
204 public override void link(PhysicsActor obj) { 207 {
205 BSPrim parent = obj as BSPrim; 208 CrossingFailures++;
206 if (parent != null) 209 if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
207 { 210 {
208 BSPhysObject parentBefore = Linkset.LinksetRoot; 211 base.RaiseOutOfBounds(RawPosition);
209 int childrenBefore = Linkset.NumberOfChildren; 212 }
210 213 else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
211 Linkset = parent.Linkset.AddMeToLinkset(this); 214 {
212 215 m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
213 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
214 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
215 } 216 }
216 return; 217 return;
217 } 218 }
218 219
220 // link me to the specified parent
221 public override void link(PhysicsActor obj) {
222 }
223
219 // delink me from my linkset 224 // delink me from my linkset
220 public override void delink() { 225 public override void delink() {
221 // TODO: decide if this parent checking needs to happen at taint time
222 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
223
224 BSPhysObject parentBefore = Linkset.LinksetRoot;
225 int childrenBefore = Linkset.NumberOfChildren;
226
227 Linkset = Linkset.RemoveMeFromLinkset(this);
228
229 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
230 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
231 return;
232 } 226 }
233 227
234 // Set motion values to zero. 228 // Set motion values to zero.
@@ -244,7 +238,8 @@ public sealed class BSPrim : BSPhysObject
244 // Zero some other properties in the physics engine 238 // Zero some other properties in the physics engine
245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 239 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
246 { 240 {
247 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 241 if (PhysBody.HasPhysicalBody)
242 PhysicsScene.PE.ClearAllForces(PhysBody);
248 }); 243 });
249 } 244 }
250 public override void ZeroAngularMotion(bool inTaintTime) 245 public override void ZeroAngularMotion(bool inTaintTime)
@@ -253,16 +248,107 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 248 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 249 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 250 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 251 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 252 if (PhysBody.HasPhysicalBody)
253 {
254 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
255 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
256 }
258 }); 257 });
259 } 258 }
260 259
260 bool TryExperimentalLockAxisCode = false;
261 BSConstraint LockAxisConstraint = null;
261 public override void LockAngularMotion(OMV.Vector3 axis) 262 public override void LockAngularMotion(OMV.Vector3 axis)
262 { 263 {
263 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 264 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
265
266 // "1" means free, "0" means locked
267 OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f);
268 if (axis.X != 1) locking.X = 0f;
269 if (axis.Y != 1) locking.Y = 0f;
270 if (axis.Z != 1) locking.Z = 0f;
271 LockedAxis = locking;
272
273 if (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree)
274 {
275 // Lock that axis by creating a 6DOF constraint that has one end in the world and
276 // the other in the object.
277 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
278 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
279
280 PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
281 {
282 CleanUpLockAxisPhysicals(true /* inTaintTime */);
283
284 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(PhysicsScene.World, PhysBody,
285 OMV.Vector3.Zero, OMV.Quaternion.Inverse(RawOrientation),
286 true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
287 LockAxisConstraint = axisConstrainer;
288 PhysicsScene.Constraints.AddConstraint(LockAxisConstraint);
289
290 // The constraint is tied to the world and oriented to the prim.
291
292 // Free to move linearly
293 OMV.Vector3 linearLow = OMV.Vector3.Zero;
294 OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize;
295 axisConstrainer.SetLinearLimits(linearLow, linearHigh);
296
297 // Angular with some axis locked
298 float f2PI = (float)Math.PI * 2f;
299 OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI);
300 OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI);
301 if (LockedAxis.X != 1f)
302 {
303 angularLow.X = 0f;
304 angularHigh.X = 0f;
305 }
306 if (LockedAxis.Y != 1f)
307 {
308 angularLow.Y = 0f;
309 angularHigh.Y = 0f;
310 }
311 if (LockedAxis.Z != 1f)
312 {
313 angularLow.Z = 0f;
314 angularHigh.Z = 0f;
315 }
316 axisConstrainer.SetAngularLimits(angularLow, angularHigh);
317
318 DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}",
319 LocalID, linearLow, linearHigh, angularLow, angularHigh);
320
321 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
322 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
323
324 axisConstrainer.RecomputeConstraintVariables(RawMass);
325 });
326 }
327 else
328 {
329 // Everything seems unlocked
330 CleanUpLockAxisPhysicals(false /* inTaintTime */);
331 }
332
264 return; 333 return;
265 } 334 }
335 // Get rid of any constraint built for LockAxis
336 // Most often the constraint is removed when the constraint collection is cleaned for this prim.
337 private void CleanUpLockAxisPhysicals(bool inTaintTime)
338 {
339 if (LockAxisConstraint != null)
340 {
341 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CleanUpLockAxisPhysicals", delegate()
342 {
343 if (LockAxisConstraint != null)
344 {
345 PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
346 LockAxisConstraint = null;
347 DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", LocalID);
348 }
349 });
350 }
351 }
266 352
267 public override OMV.Vector3 RawPosition 353 public override OMV.Vector3 RawPosition
268 { 354 {
@@ -271,41 +357,41 @@ public sealed class BSPrim : BSPhysObject
271 } 357 }
272 public override OMV.Vector3 Position { 358 public override OMV.Vector3 Position {
273 get { 359 get {
274 // child prims move around based on their parent. Need to get the latest location
275 if (!Linkset.IsRoot(this))
276 _position = Linkset.Position(this);
277
278 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 360 // 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); 361 // _position = ForcePosition;
280 return _position; 362 return _position;
281 } 363 }
282 set { 364 set {
283 // If the position must be forced into the physics engine, use ForcePosition. 365 // If the position must be forced into the physics engine, use ForcePosition.
366 // All positions are given in world positions.
284 if (_position == value) 367 if (_position == value)
285 { 368 {
369 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
286 return; 370 return;
287 } 371 }
288 _position = value; 372 _position = value;
289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
290 PositionSanityCheck(false); 373 PositionSanityCheck(false);
374
291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 375 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
292 { 376 {
293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 377 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 378 ForcePosition = _position;
295 ActivateIfPhysical(false);
296 }); 379 });
297 } 380 }
298 } 381 }
382
299 public override OMV.Vector3 ForcePosition { 383 public override OMV.Vector3 ForcePosition {
300 get { 384 get {
301 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 385 _position = PhysicsScene.PE.GetPosition(PhysBody);
302 return _position; 386 return _position;
303 } 387 }
304 set { 388 set {
305 _position = value; 389 _position = value;
306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. 390 if (PhysBody.HasPhysicalBody)
307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 391 {
308 ActivateIfPhysical(false); 392 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
393 ActivateIfPhysical(false);
394 }
309 } 395 }
310 } 396 }
311 397
@@ -316,119 +402,231 @@ public sealed class BSPrim : BSPhysObject
316 { 402 {
317 bool ret = false; 403 bool ret = false;
318 404
319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 405 // We don't care where non-physical items are placed
406 if (!IsPhysicallyActive)
407 return ret;
408
409 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
410 {
411 // The physical object is out of the known/simulated area.
412 // Upper levels of code will handle the transition to other areas so, for
413 // the time, we just ignore the position.
414 return ret;
415 }
416
417 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
320 OMV.Vector3 upForce = OMV.Vector3.Zero; 418 OMV.Vector3 upForce = OMV.Vector3.Zero;
321 if (Position.Z < terrainHeight) 419 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
420 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
322 { 421 {
323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 422 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
324 float targetHeight = terrainHeight + (Size.Z / 2f); 423 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 424 // If the object is below ground it just has to be moved up because pushing will
326 upForce.Z = (terrainHeight - Position.Z) * 1f; 425 // not get it through the terrain
426 _position.Z = targetHeight;
427 if (inTaintTime)
428 {
429 ForcePosition = _position;
430 }
431 // If we are throwing the object around, zero its other forces
432 ZeroMotion(inTaintTime);
327 ret = true; 433 ret = true;
328 } 434 }
329 435
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 436 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 437 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 438 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 439 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 440 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
335 { 441 {
336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec. 442 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f; 443 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
444
445 // Apply upforce and overcome gravity.
446 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
447 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
448 AddForce(correctionForce, false, inTaintTime);
338 ret = true; 449 ret = true;
339 } 450 }
340 } 451 }
341 452
342 // TODO: check for out of bounds 453 return ret;
454 }
455
456 // Occasionally things will fly off and really get lost.
457 // Find the wanderers and bring them back.
458 // Return 'true' if some parameter need some sanity.
459 private bool ExtremeSanityCheck(bool inTaintTime)
460 {
461 bool ret = false;
343 462
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. 463 uint wayOutThere = Constants.RegionSize * Constants.RegionSize;
345 if (ret) 464 // There have been instances of objects getting thrown way out of bounds and crashing
465 // the border crossing code.
466 if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere
467 || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere
468 || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere)
346 { 469 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() 470 _position = new OMV.Vector3(10, 10, 50);
348 { 471 ZeroMotion(inTaintTime);
349 // Apply upforce and overcome gravity. 472 ret = true;
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; 473 }
351 }); 474 if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity)
475 {
476 _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity);
477 ret = true;
352 } 478 }
479 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
480 {
481 _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
482 ret = true;
483 }
484
353 return ret; 485 return ret;
354 } 486 }
355 487
356 // Return the effective mass of the object. 488 // Return the effective mass of the object.
357 // If there are multiple items in the linkset, add them together for the root 489 // The definition of this call is to return the mass of the prim.
490 // If the simulator cares about the mass of the linkset, it will sum it itself.
358 public override float Mass 491 public override float Mass
359 { 492 {
360 get 493 get { return _mass; }
361 { 494 }
362 return Linkset.LinksetMass; 495 // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
363 // return _mass; 496 public virtual float TotalMass
364 } 497 {
498 get { return _mass; }
365 } 499 }
366
367 // used when we only want this prim's mass and not the linkset thing 500 // used when we only want this prim's mass and not the linkset thing
368 public override float RawMass { 501 public override float RawMass {
369 get { return _mass; } 502 get { return _mass; }
370 } 503 }
371 // Set the physical mass to the passed mass. 504 // Set the physical mass to the passed mass.
372 // Note that this does not change _mass! 505 // Note that this does not change _mass!
373 public override void UpdatePhysicalMassProperties(float physMass) 506 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
374 { 507 {
375 if (IsStatic) 508 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
376 { 509 {
377 Inertia = OMV.Vector3.Zero; 510 if (IsStatic)
378 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); 511 {
379 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); 512 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity);
513 Inertia = OMV.Vector3.Zero;
514 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia);
515 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
516 }
517 else
518 {
519 if (inWorld)
520 {
521 // Changing interesting properties doesn't change proxy and collision cache
522 // information. The Bullet solution is to re-add the object to the world
523 // after parameters are changed.
524 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
525 }
526
527 // The computation of mass props requires gravity to be set on the object.
528 Gravity = ComputeGravity(Buoyancy);
529 PhysicsScene.PE.SetGravity(PhysBody, Gravity);
530
531 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
532 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
533 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
534
535 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
536 LocalID, physMass, Inertia, Gravity, inWorld);
537
538 if (inWorld)
539 {
540 AddObjectToPhysicalWorld();
541 }
542 }
380 } 543 }
381 else 544 }
545
546 // Return what gravity should be set to this very moment
547 public OMV.Vector3 ComputeGravity(float buoyancy)
548 {
549 OMV.Vector3 ret = PhysicsScene.DefaultGravity;
550
551 if (!IsStatic)
382 { 552 {
383 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 553 ret *= (1f - buoyancy);
384 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); 554 ret *= GravModifier;
385 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
386 // center of mass is at the zero of the object
387 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
388 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia);
389 } 555 }
556
557 return ret;
390 } 558 }
391 559
392 // Is this used? 560 // Is this used?
393 public override OMV.Vector3 CenterOfMass 561 public override OMV.Vector3 CenterOfMass
394 { 562 {
395 get { return Linkset.CenterOfMass; } 563 get { return RawPosition; }
396 } 564 }
397 565
398 // Is this used? 566 // Is this used?
399 public override OMV.Vector3 GeometricCenter 567 public override OMV.Vector3 GeometricCenter
400 { 568 {
401 get { return Linkset.GeometricCenter; } 569 get { return RawPosition; }
402 } 570 }
403 571
404 public override OMV.Vector3 Force { 572 public override OMV.Vector3 Force {
405 get { return _force; } 573 get { return _force; }
406 set { 574 set {
407 _force = value; 575 _force = value;
408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 576 if (_force != OMV.Vector3.Zero)
409 { 577 {
410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 578 // If the force is non-zero, it must be reapplied each tick because
411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 579 // Bullet clears the forces applied last frame.
412 }); 580 RegisterPreStepAction("BSPrim.setForce", LocalID,
581 delegate(float timeStep)
582 {
583 if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
584 {
585 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
586 return;
587 }
588
589 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
590 if (PhysBody.HasPhysicalBody)
591 {
592 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
593 ActivateIfPhysical(false);
594 }
595 }
596 );
597 }
598 else
599 {
600 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
601 }
413 } 602 }
414 } 603 }
415 604
416 public override int VehicleType { 605 public override int VehicleType {
417 get { 606 get {
418 return (int)_vehicle.Type; // if we are a vehicle, return that type 607 return (int)VehicleController.Type; // if we are a vehicle, return that type
419 } 608 }
420 set { 609 set {
421 Vehicle type = (Vehicle)value; 610 Vehicle type = (Vehicle)value;
422 611
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() 612 PhysicsScene.TaintedObject("setVehicleType", delegate()
427 { 613 {
428 // Done at taint time so we're sure the physics engine is not using the variables 614 // 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. 615 // Vehicle code changes the parameters for this vehicle type.
430 _vehicle.ProcessTypeChange(type); 616 VehicleController.ProcessTypeChange(type);
431 ActivateIfPhysical(false); 617 ActivateIfPhysical(false);
618
619 // If an active vehicle, register the vehicle code to be called before each step
620 if (VehicleController.Type == Vehicle.TYPE_NONE)
621 {
622 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
623 UnRegisterPostStepAction("BSPrim.Vehicle", LocalID);
624 }
625 else
626 {
627 RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step);
628 RegisterPostStepAction("BSPrim.Vehicle", LocalID, VehicleController.PostStep);
629 }
432 }); 630 });
433 } 631 }
434 } 632 }
@@ -436,7 +634,7 @@ public sealed class BSPrim : BSPhysObject
436 { 634 {
437 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 635 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
438 { 636 {
439 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 637 VehicleController.ProcessFloatVehicleParam((Vehicle)param, value);
440 ActivateIfPhysical(false); 638 ActivateIfPhysical(false);
441 }); 639 });
442 } 640 }
@@ -444,7 +642,7 @@ public sealed class BSPrim : BSPhysObject
444 { 642 {
445 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 643 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
446 { 644 {
447 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 645 VehicleController.ProcessVectorVehicleParam((Vehicle)param, value);
448 ActivateIfPhysical(false); 646 ActivateIfPhysical(false);
449 }); 647 });
450 } 648 }
@@ -452,7 +650,7 @@ public sealed class BSPrim : BSPhysObject
452 { 650 {
453 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 651 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
454 { 652 {
455 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 653 VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation);
456 ActivateIfPhysical(false); 654 ActivateIfPhysical(false);
457 }); 655 });
458 } 656 }
@@ -460,27 +658,10 @@ public sealed class BSPrim : BSPhysObject
460 { 658 {
461 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 659 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
462 { 660 {
463 _vehicle.ProcessVehicleFlags(param, remove); 661 VehicleController.ProcessVehicleFlags(param, remove);
464 }); 662 });
465 } 663 }
466 664
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 665 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
485 public override void SetVolumeDetect(int param) { 666 public override void SetVolumeDetect(int param) {
486 bool newValue = (param != 0); 667 bool newValue = (param != 0);
@@ -495,6 +676,81 @@ public sealed class BSPrim : BSPhysObject
495 } 676 }
496 return; 677 return;
497 } 678 }
679 public override void SetMaterial(int material)
680 {
681 base.SetMaterial(material);
682 PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate()
683 {
684 UpdatePhysicalParameters();
685 });
686 }
687 public override float Friction
688 {
689 get { return base.Friction; }
690 set
691 {
692 if (base.Friction != value)
693 {
694 base.Friction = value;
695 PhysicsScene.TaintedObject("BSPrim.setFriction", delegate()
696 {
697 UpdatePhysicalParameters();
698 });
699 }
700 }
701 }
702 public override float Restitution
703 {
704 get { return base.Restitution; }
705 set
706 {
707 if (base.Restitution != value)
708 {
709 base.Restitution = value;
710 PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate()
711 {
712 UpdatePhysicalParameters();
713 });
714 }
715 }
716 }
717 // The simulator/viewer keep density as 100kg/m3.
718 // Remember to use BSParam.DensityScaleFactor to create the physical density.
719 public override float Density
720 {
721 get { return base.Density; }
722 set
723 {
724 if (base.Density != value)
725 {
726 base.Density = value;
727 PhysicsScene.TaintedObject("BSPrim.setDensity", delegate()
728 {
729 UpdatePhysicalParameters();
730 });
731 }
732 }
733 }
734 public override float GravModifier
735 {
736 get { return base.GravModifier; }
737 set
738 {
739 if (base.GravModifier != value)
740 {
741 base.GravModifier = value;
742 PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate()
743 {
744 UpdatePhysicalParameters();
745 });
746 }
747 }
748 }
749 public override OMV.Vector3 RawVelocity
750 {
751 get { return _velocity; }
752 set { _velocity = value; }
753 }
498 public override OMV.Vector3 Velocity { 754 public override OMV.Vector3 Velocity {
499 get { return _velocity; } 755 get { return _velocity; }
500 set { 756 set {
@@ -502,30 +758,53 @@ public sealed class BSPrim : BSPhysObject
502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 758 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
503 { 759 {
504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 760 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 761 ForceVelocity = _velocity;
506 }); 762 });
507 } 763 }
508 } 764 }
509 public override OMV.Vector3 ForceVelocity { 765 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 766 get { return _velocity; }
511 set { 767 set {
512 _velocity = value; 768 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
513 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 769
770 _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
771 if (PhysBody.HasPhysicalBody)
772 {
773 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity);
774 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
775 ActivateIfPhysical(false);
776 }
514 } 777 }
515 } 778 }
516 public override OMV.Vector3 Torque { 779 public override OMV.Vector3 Torque {
517 get { return _torque; } 780 get { return _torque; }
518 set { 781 set {
519 _torque = value; 782 _torque = value;
520 AddAngularForce(_torque, false, false); 783 if (_torque != OMV.Vector3.Zero)
784 {
785 // If the torque is non-zero, it must be reapplied each tick because
786 // Bullet clears the forces applied last frame.
787 RegisterPreStepAction("BSPrim.setTorque", LocalID,
788 delegate(float timeStep)
789 {
790 if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
791 {
792 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
793 return;
794 }
795
796 if (PhysBody.HasPhysicalBody)
797 AddAngularForce(_torque, false, true);
798 }
799 );
800 }
801 else
802 {
803 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
804 }
521 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 805 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
522 } 806 }
523 } 807 }
524 public override float CollisionScore {
525 get { return _collisionScore; }
526 set { _collisionScore = value;
527 }
528 }
529 public override OMV.Vector3 Acceleration { 808 public override OMV.Vector3 Acceleration {
530 get { return _acceleration; } 809 get { return _acceleration; }
531 set { _acceleration = value; } 810 set { _acceleration = value; }
@@ -537,23 +816,16 @@ public sealed class BSPrim : BSPhysObject
537 } 816 }
538 public override OMV.Quaternion Orientation { 817 public override OMV.Quaternion Orientation {
539 get { 818 get {
540 // Children move around because tied to parent. Get a fresh value.
541 if (!Linkset.IsRoot(this))
542 {
543 _orientation = Linkset.Orientation(this);
544 }
545 return _orientation; 819 return _orientation;
546 } 820 }
547 set { 821 set {
548 if (_orientation == value) 822 if (_orientation == value)
549 return; 823 return;
550 _orientation = value; 824 _orientation = value;
551 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 825
552 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 826 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
553 { 827 {
554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 828 ForceOrientation = _orientation;
555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
557 }); 829 });
558 } 830 }
559 } 831 }
@@ -562,13 +834,14 @@ public sealed class BSPrim : BSPhysObject
562 { 834 {
563 get 835 get
564 { 836 {
565 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 837 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
566 return _orientation; 838 return _orientation;
567 } 839 }
568 set 840 set
569 { 841 {
570 _orientation = value; 842 _orientation = value;
571 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 843 if (PhysBody.HasPhysicalBody)
844 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
572 } 845 }
573 } 846 }
574 public override int PhysicsActorType { 847 public override int PhysicsActorType {
@@ -583,10 +856,11 @@ public sealed class BSPrim : BSPhysObject
583 _isPhysical = value; 856 _isPhysical = value;
584 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 857 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
585 { 858 {
586 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 859 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
587 SetObjectDynamic(true); 860 SetObjectDynamic(true);
588 // whether phys-to-static or static-to-phys, the object is not moving. 861 // whether phys-to-static or static-to-phys, the object is not moving.
589 ZeroMotion(true); 862 ZeroMotion(true);
863
590 }); 864 });
591 } 865 }
592 } 866 }
@@ -604,6 +878,12 @@ public sealed class BSPrim : BSPhysObject
604 get { return !IsPhantom && !_isVolumeDetect; } 878 get { return !IsPhantom && !_isVolumeDetect; }
605 } 879 }
606 880
881 // The object is moving and is actively being dynamic in the physical world
882 public override bool IsPhysicallyActive
883 {
884 get { return !_isSelected && IsPhysical; }
885 }
886
607 // Make gravity work if the object is physical and not selected 887 // Make gravity work if the object is physical and not selected
608 // Called at taint-time!! 888 // Called at taint-time!!
609 private void SetObjectDynamic(bool forceRebuild) 889 private void SetObjectDynamic(bool forceRebuild)
@@ -618,19 +898,24 @@ public sealed class BSPrim : BSPhysObject
618 // isSolid: other objects bounce off of this object 898 // isSolid: other objects bounce off of this object
619 // isVolumeDetect: other objects pass through but can generate collisions 899 // isVolumeDetect: other objects pass through but can generate collisions
620 // collisionEvents: whether this object returns collision events 900 // collisionEvents: whether this object returns collision events
621 private void UpdatePhysicalParameters() 901 public virtual void UpdatePhysicalParameters()
622 { 902 {
623 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); 903 if (!PhysBody.HasPhysicalBody)
904 {
905 // This would only happen if updates are called for during initialization when the body is not set up yet.
906 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
907 return;
908 }
624 909
625 // Mangling all the physical properties requires the object not be in the physical world. 910 // 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). 911 // 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); 912 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
628 913
629 // Set up the object physicalness (does gravity and collisions move this object) 914 // Set up the object physicalness (does gravity and collisions move this object)
630 MakeDynamic(IsStatic); 915 MakeDynamic(IsStatic);
631 916
632 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) 917 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
633 _vehicle.Refresh(); 918 VehicleController.Refresh();
634 919
635 // Arrange for collision events if the simulator wants them 920 // Arrange for collision events if the simulator wants them
636 EnableCollisions(SubscribedEvents()); 921 EnableCollisions(SubscribedEvents());
@@ -638,25 +923,13 @@ public sealed class BSPrim : BSPhysObject
638 // Make solid or not (do things bounce off or pass through this object). 923 // Make solid or not (do things bounce off or pass through this object).
639 MakeSolid(IsSolid); 924 MakeSolid(IsSolid);
640 925
641 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 926 AddObjectToPhysicalWorld();
642 927
643 // Rebuild its shape 928 // Rebuild its shape
644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 929 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
652 // Recompute any linkset parameters.
653 // When going from non-physical to physical, this re-enables the constraints that
654 // had been automatically disabled when the mass was set to zero.
655 // For compound based linksets, this enables and disables interactions of the children.
656 Linkset.Refresh(this);
657 930
658 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 931 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); 932 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
660 } 933 }
661 934
662 // "Making dynamic" means changing to and from static. 935 // "Making dynamic" means changing to and from static.
@@ -664,79 +937,78 @@ public sealed class BSPrim : BSPhysObject
664 // When dynamic, the object can fall and be pushed by others. 937 // When dynamic, the object can fall and be pushed by others.
665 // This is independent of its 'solidness' which controls what passes through 938 // This is independent of its 'solidness' which controls what passes through
666 // this object and what interacts with it. 939 // this object and what interacts with it.
667 private void MakeDynamic(bool makeStatic) 940 protected virtual void MakeDynamic(bool makeStatic)
668 { 941 {
669 if (makeStatic) 942 if (makeStatic)
670 { 943 {
671 // Become a Bullet 'static' object type 944 // Become a Bullet 'static' object type
672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 945 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
673 // Stop all movement 946 // Stop all movement
674 ZeroMotion(true); 947 ZeroMotion(true);
675 // Center of mass is at the center of the object 948
676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 949 // Set various physical properties so other object interact properly
950 PhysicsScene.PE.SetFriction(PhysBody, Friction);
951 PhysicsScene.PE.SetRestitution(PhysBody, Restitution);
952 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
953
677 // Mass is zero which disables a bunch of physics stuff in Bullet 954 // Mass is zero which disables a bunch of physics stuff in Bullet
678 UpdatePhysicalMassProperties(0f); 955 UpdatePhysicalMassProperties(0f, false);
679 // Set collision detection parameters 956 // Set collision detection parameters
680 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 957 if (BSParam.CcdMotionThreshold > 0f)
681 { 958 {
682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 959 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 960 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
684 } 961 }
685 // There can be special things needed for implementing linksets 962
686 Linkset.MakeStatic(this);
687 // The activation state is 'disabled' so Bullet will not try to act on it. 963 // The activation state is 'disabled' so Bullet will not try to act on it.
688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 964 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
689 // Start it out sleeping and physical actions could wake it up. 965 // Start it out sleeping and physical actions could wake it up.
690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 966 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
691 967
692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 968 // This collides like a static object
693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 969 PhysBody.collisionType = CollisionType.Static;
694 } 970 }
695 else 971 else
696 { 972 {
697 // Not a Bullet static object 973 // Not a Bullet static object
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 974 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
699 975
700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 976 // Set various physical properties so other object interact properly
701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 977 PhysicsScene.PE.SetFriction(PhysBody, Friction);
702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 978 PhysicsScene.PE.SetRestitution(PhysBody, Restitution);
979 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
703 980
704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 981 // 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 982 // Since this can be called multiple times, only zero forces when becoming physical
706 // BulletSimAPI.ClearAllForces2(BSBody.ptr); 983 // PhysicsScene.PE.ClearAllForces(BSBody);
707 984
708 // For good measure, make sure the transform is set through to the motion state 985 // For good measure, make sure the transform is set through to the motion state
709 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 986 ForcePosition = _position;
710 987 ForceVelocity = _velocity;
711 // Center of mass is at the center of the object 988 ForceRotationalVelocity = _rotationalVelocity;
712 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
713 989
714 // A dynamic object has mass 990 // A dynamic object has mass
715 UpdatePhysicalMassProperties(RawMass); 991 UpdatePhysicalMassProperties(RawMass, false);
716 992
717 // Set collision detection parameters 993 // Set collision detection parameters
718 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 994 if (BSParam.CcdMotionThreshold > 0f)
719 { 995 {
720 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 996 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
721 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 997 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
722 } 998 }
723 999
724 // Various values for simulation limits 1000 // Various values for simulation limits
725 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 1001 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
726 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); 1002 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 1003 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 1004 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
729 1005
730 // There might be special things needed for implementing linksets. 1006 // This collides like an object.
731 Linkset.MakeDynamic(this); 1007 PhysBody.collisionType = CollisionType.Dynamic;
732 1008
733 // Force activation of the object so Bullet will act on it. 1009 // Force activation of the object so Bullet will act on it.
734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 1010 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 1011 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
736 // BulletSimAPI.Activate2(BSBody.ptr, true);
737
738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
740 } 1012 }
741 } 1013 }
742 1014
@@ -746,7 +1018,7 @@ public sealed class BSPrim : BSPhysObject
746 // the functions after this one set up the state of a possibly newly created collision body. 1018 // the functions after this one set up the state of a possibly newly created collision body.
747 private void MakeSolid(bool makeSolid) 1019 private void MakeSolid(bool makeSolid)
748 { 1020 {
749 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); 1021 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody);
750 if (makeSolid) 1022 if (makeSolid)
751 { 1023 {
752 // Verify the previous code created the correct shape for this type of thing. 1024 // Verify the previous code created the correct shape for this type of thing.
@@ -754,7 +1026,7 @@ public sealed class BSPrim : BSPhysObject
754 { 1026 {
755 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 1027 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
756 } 1028 }
757 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 1029 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
758 } 1030 }
759 else 1031 else
760 { 1032 {
@@ -762,9 +1034,10 @@ public sealed class BSPrim : BSPhysObject
762 { 1034 {
763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 1035 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
764 } 1036 }
765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 1037 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 1038
767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 1039 // Change collision info from a static object to a ghosty collision object
1040 PhysBody.collisionType = CollisionType.VolumeDetect;
768 } 1041 }
769 } 1042 }
770 1043
@@ -773,8 +1046,8 @@ public sealed class BSPrim : BSPhysObject
773 // Called in taint-time!! 1046 // Called in taint-time!!
774 private void ActivateIfPhysical(bool forceIt) 1047 private void ActivateIfPhysical(bool forceIt)
775 { 1048 {
776 if (IsPhysical) 1049 if (IsPhysical && PhysBody.HasPhysicalBody)
777 BulletSimAPI.Activate2(PhysBody.ptr, forceIt); 1050 PhysicsScene.PE.Activate(PhysBody, forceIt);
778 } 1051 }
779 1052
780 // Turn on or off the flag controlling whether collision events are returned to the simulator. 1053 // Turn on or off the flag controlling whether collision events are returned to the simulator.
@@ -782,11 +1055,27 @@ public sealed class BSPrim : BSPhysObject
782 { 1055 {
783 if (wantsCollisionEvents) 1056 if (wantsCollisionEvents)
784 { 1057 {
785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 1058 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1059 }
1060 else
1061 {
1062 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1063 }
1064 }
1065
1066 // Add me to the physical world.
1067 // Object MUST NOT already be in the world.
1068 // This routine exists because some assorted properties get mangled by adding to the world.
1069 internal void AddObjectToPhysicalWorld()
1070 {
1071 if (PhysBody.HasPhysicalBody)
1072 {
1073 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
786 } 1074 }
787 else 1075 else
788 { 1076 {
789 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 1077 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
1078 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
790 } 1079 }
791 } 1080 }
792 1081
@@ -805,18 +1094,6 @@ public sealed class BSPrim : BSPhysObject
805 get { return _throttleUpdates; } 1094 get { return _throttleUpdates; }
806 set { _throttleUpdates = value; } 1095 set { _throttleUpdates = value; }
807 } 1096 }
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 { 1097 public bool IsPhantom {
821 get { 1098 get {
822 // SceneObjectPart removes phantom objects from the physics scene 1099 // SceneObjectPart removes phantom objects from the physics scene
@@ -831,32 +1108,23 @@ public sealed class BSPrim : BSPhysObject
831 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 1108 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
832 { 1109 {
833 if (_floatOnWater) 1110 if (_floatOnWater)
834 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 1111 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
835 else 1112 else
836 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 1113 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
837 }); 1114 });
838 } 1115 }
839 } 1116 }
840 public override OMV.Vector3 RotationalVelocity { 1117 public override OMV.Vector3 RotationalVelocity {
841 get { 1118 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; 1119 return _rotationalVelocity;
852 } 1120 }
853 set { 1121 set {
854 _rotationalVelocity = value; 1122 _rotationalVelocity = value;
1123 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
855 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 1124 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 1125 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
857 { 1126 {
858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 1127 ForceRotationalVelocity = _rotationalVelocity;
859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
860 }); 1128 });
861 } 1129 }
862 } 1130 }
@@ -865,8 +1133,14 @@ public sealed class BSPrim : BSPhysObject
865 return _rotationalVelocity; 1133 return _rotationalVelocity;
866 } 1134 }
867 set { 1135 set {
868 _rotationalVelocity = value; 1136 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
869 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 1137 if (PhysBody.HasPhysicalBody)
1138 {
1139 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1140 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1141 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1142 ActivateIfPhysical(false);
1143 }
870 } 1144 }
871 } 1145 }
872 public override bool Kinematic { 1146 public override bool Kinematic {
@@ -890,27 +1164,130 @@ public sealed class BSPrim : BSPhysObject
890 set { 1164 set {
891 _buoyancy = value; 1165 _buoyancy = value;
892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 1166 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
893 // Buoyancy is faked by changing the gravity applied to the object 1167 // Force the recalculation of the various inertia,etc variables in the object
894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 1168 UpdatePhysicalMassProperties(RawMass, true);
895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 1169 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1170 ActivateIfPhysical(false);
896 } 1171 }
897 } 1172 }
898 1173
899 // Used for MoveTo 1174 // Used for MoveTo
900 public override OMV.Vector3 PIDTarget { 1175 public override OMV.Vector3 PIDTarget {
901 set { _PIDTarget = value; } 1176 set
902 } 1177 {
903 public override bool PIDActive { 1178 // TODO: add a sanity check -- don't move more than a region or something like that.
904 set { _usePID = value; } 1179 _PIDTarget = value;
1180 }
905 } 1181 }
906 public override float PIDTau { 1182 public override float PIDTau {
907 set { _PIDTau = value; } 1183 set { _PIDTau = value; }
908 } 1184 }
1185 public override bool PIDActive {
1186 set {
1187 if (value)
1188 {
1189 // We're taking over after this.
1190 ZeroMotion(true);
1191
1192 _targetMotor = new BSVMotor("BSPrim.PIDTarget",
1193 _PIDTau, // timeScale
1194 BSMotor.Infinite, // decay time scale
1195 BSMotor.InfiniteVector, // friction timescale
1196 1f // efficiency
1197 );
1198 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1199 _targetMotor.SetTarget(_PIDTarget);
1200 _targetMotor.SetCurrent(RawPosition);
1201 /*
1202 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1203 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1204
1205 _targetMotor.SetTarget(_PIDTarget);
1206 _targetMotor.SetCurrent(RawPosition);
1207 _targetMotor.TimeScale = _PIDTau;
1208 _targetMotor.Efficiency = 1f;
1209 */
1210
1211 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1212 {
1213 if (!IsPhysicallyActive)
1214 {
1215 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1216 return;
1217 }
1218
1219 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1220
1221 // 'movePosition' is where we'd like the prim to be at this moment.
1222 OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
1223
1224 // If we are very close to our target, turn off the movement motor.
1225 if (_targetMotor.ErrorIsZero())
1226 {
1227 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
1228 LocalID, movePosition, RawPosition, Mass);
1229 ForcePosition = _targetMotor.TargetValue;
1230 _targetMotor.Enabled = false;
1231 }
1232 else
1233 {
1234 _position = movePosition;
1235 PositionSanityCheck(true /* intaintTime */);
1236 ForcePosition = _position;
1237 }
1238 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1239 });
1240 }
1241 else
1242 {
1243 // Stop any targetting
1244 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1245 }
1246 }
1247 }
909 1248
910 // Used for llSetHoverHeight and maybe vehicle height 1249 // Used for llSetHoverHeight and maybe vehicle height
911 // Hover Height will override MoveTo target's Z 1250 // Hover Height will override MoveTo target's Z
912 public override bool PIDHoverActive { 1251 public override bool PIDHoverActive {
913 set { _useHoverPID = value; } 1252 set {
1253 if (value)
1254 {
1255 // Turning the target on
1256 _hoverMotor = new BSFMotor("BSPrim.Hover",
1257 _PIDHoverTau, // timeScale
1258 BSMotor.Infinite, // decay time scale
1259 BSMotor.Infinite, // friction timescale
1260 1f // efficiency
1261 );
1262 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1263 _hoverMotor.SetCurrent(RawPosition.Z);
1264 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1265
1266 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1267 {
1268 // Don't do hovering while the object is selected.
1269 if (!IsPhysicallyActive)
1270 return;
1271
1272 _hoverMotor.SetCurrent(RawPosition.Z);
1273 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1274 float targetHeight = _hoverMotor.Step(timeStep);
1275
1276 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1277 // Compute the amount of force to push us there.
1278 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1279 // Undo anything the object thinks it's doing at the moment
1280 moveForce = -RawVelocity.Z * Mass;
1281
1282 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1283 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1284 });
1285 }
1286 else
1287 {
1288 UnRegisterPreStepAction("BSPrim.Hover", LocalID);
1289 }
1290 }
914 } 1291 }
915 public override float PIDHoverHeight { 1292 public override float PIDHoverHeight {
916 set { _PIDHoverHeight = value; } 1293 set { _PIDHoverHeight = value; }
@@ -919,8 +1296,35 @@ public sealed class BSPrim : BSPhysObject
919 set { _PIDHoverType = value; } 1296 set { _PIDHoverType = value; }
920 } 1297 }
921 public override float PIDHoverTau { 1298 public override float PIDHoverTau {
922 set { _PIDHoverTao = value; } 1299 set { _PIDHoverTau = value; }
923 } 1300 }
1301 // Based on current position, determine what we should be hovering at now.
1302 // Must recompute often. What if we walked offa cliff>
1303 private float ComputeCurrentPIDHoverHeight()
1304 {
1305 float ret = _PIDHoverHeight;
1306 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1307
1308 switch (_PIDHoverType)
1309 {
1310 case PIDHoverType.Ground:
1311 ret = groundHeight + _PIDHoverHeight;
1312 break;
1313 case PIDHoverType.GroundAndWater:
1314 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1315 if (groundHeight > waterHeight)
1316 {
1317 ret = groundHeight + _PIDHoverHeight;
1318 }
1319 else
1320 {
1321 ret = waterHeight + _PIDHoverHeight;
1322 }
1323 break;
1324 }
1325 return ret;
1326 }
1327
924 1328
925 // For RotLookAt 1329 // For RotLookAt
926 public override OMV.Quaternion APIDTarget { set { return; } } 1330 public override OMV.Quaternion APIDTarget { set { return; } }
@@ -928,54 +1332,73 @@ public sealed class BSPrim : BSPhysObject
928 public override float APIDStrength { set { return; } } 1332 public override float APIDStrength { set { return; } }
929 public override float APIDDamping { set { return; } } 1333 public override float APIDDamping { set { return; } }
930 1334
931 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
932 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1335 public override void AddForce(OMV.Vector3 force, bool pushforce) {
933 AddForce(force, pushforce, false); 1336 // Per documentation, max force is limited.
1337 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1338
1339 // Since this force is being applied in only one step, make this a force per second.
1340 addForce /= PhysicsScene.LastTimeStep;
1341 AddForce(addForce, pushforce, false /* inTaintTime */);
934 } 1342 }
1343
935 // Applying a force just adds this to the total force on the object. 1344 // Applying a force just adds this to the total force on the object.
1345 // This added force will only last the next simulation tick.
936 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1346 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
937 // for an object, doesn't matter if force is a pushforce or not 1347 // for an object, doesn't matter if force is a pushforce or not
938 if (force.IsFinite()) 1348 if (IsPhysicallyActive)
939 {
940 // _force += force;
941 lock (m_accumulatedForces)
942 m_accumulatedForces.Add(new OMV.Vector3(force));
943 }
944 else
945 { 1349 {
946 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1350 if (force.IsFinite())
947 return;
948 }
949 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
950 {
951 OMV.Vector3 fSum = OMV.Vector3.Zero;
952 lock (m_accumulatedForces)
953 { 1351 {
954 // Sum the accumulated additional forces for one big force to apply once. 1352 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
955 foreach (OMV.Vector3 v in m_accumulatedForces) 1353
1354 OMV.Vector3 addForce = force;
1355 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
956 { 1356 {
957 fSum += v; 1357 // Bullet adds this central force to the total force for this tick
958 } 1358 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
959 m_accumulatedForces.Clear(); 1359 if (PhysBody.HasPhysicalBody)
1360 {
1361 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
1362 ActivateIfPhysical(false);
1363 }
1364 });
960 } 1365 }
961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); 1366 else
962 if (fSum != OMV.Vector3.Zero) 1367 {
963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); 1368 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
964 }); 1369 return;
1370 }
1371 }
965 } 1372 }
966 1373
967 // An impulse force is scaled by the mass of the object. 1374 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
968 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) 1375 // for an object, doesn't matter if force is a pushforce or not
969 { 1376 if (!IsPhysicallyActive)
970 OMV.Vector3 applyImpulse = impulse;
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 { 1377 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); 1378 if (impulse.IsFinite())
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); 1379 {
975 }); 1380 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1381 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1382
1383 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate()
1384 {
1385 // Bullet adds this impulse immediately to the velocity
1386 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1387 if (PhysBody.HasPhysicalBody)
1388 {
1389 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1390 ActivateIfPhysical(false);
1391 }
1392 });
1393 }
1394 else
1395 {
1396 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1397 return;
1398 }
1399 }
976 } 1400 }
977 1401
978 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
979 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1402 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
980 AddAngularForce(force, pushforce, false); 1403 AddAngularForce(force, pushforce, false);
981 } 1404 }
@@ -983,42 +1406,38 @@ public sealed class BSPrim : BSPhysObject
983 { 1406 {
984 if (force.IsFinite()) 1407 if (force.IsFinite())
985 { 1408 {
986 // _force += force; 1409 OMV.Vector3 angForce = force;
987 lock (m_accumulatedAngularForces) 1410 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
988 m_accumulatedAngularForces.Add(new OMV.Vector3(force)); 1411 {
1412 if (PhysBody.HasPhysicalBody)
1413 {
1414 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1415 PhysicsScene.PE.ApplyTorque(PhysBody, angForce);
1416 ActivateIfPhysical(false);
1417 }
1418 });
989 } 1419 }
990 else 1420 else
991 { 1421 {
992 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1422 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
993 return; 1423 return;
994 } 1424 }
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 } 1425 }
1426
1015 // A torque impulse. 1427 // A torque impulse.
1428 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1429 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1430 // Computed as: angularVelocity += impulse * inertia;
1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1431 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 { 1432 {
1018 OMV.Vector3 applyImpulse = impulse; 1433 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1434 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 { 1435 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); 1436 if (PhysBody.HasPhysicalBody)
1437 {
1438 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1439 ActivateIfPhysical(false);
1440 }
1022 }); 1441 });
1023 } 1442 }
1024 1443
@@ -1301,23 +1720,10 @@ public sealed class BSPrim : BSPhysObject
1301 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; 1720 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1302 volume *= (profileEnd - profileBegin); 1721 volume *= (profileEnd - profileBegin);
1303 1722
1304 returnMass = _density * volume; 1723 returnMass = Density * BSParam.DensityScaleFactor * volume;
1305 1724 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1306 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1307 if (IsRootOfLinkset)
1308 {
1309 foreach (BSPrim prim in _childrenPrims)
1310 {
1311 returnMass += prim.CalculateMass();
1312 }
1313 }
1314 */
1315
1316 if (returnMass <= 0)
1317 returnMass = 0.0001f;
1318 1725
1319 if (returnMass > PhysicsScene.MaximumObjectMass) 1726 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1320 returnMass = PhysicsScene.MaximumObjectMass;
1321 1727
1322 return returnMass; 1728 return returnMass;
1323 }// end CalculateMass 1729 }// end CalculateMass
@@ -1326,135 +1732,73 @@ public sealed class BSPrim : BSPhysObject
1326 // Rebuild the geometry and object. 1732 // Rebuild the geometry and object.
1327 // This is called when the shape changes so we need to recreate the mesh/hull. 1733 // This is called when the shape changes so we need to recreate the mesh/hull.
1328 // Called at taint-time!!! 1734 // Called at taint-time!!!
1329 private void CreateGeomAndObject(bool forceRebuild) 1735 public void CreateGeomAndObject(bool forceRebuild)
1330 { 1736 {
1331 // If this prim is part of a linkset, we must remove and restore the physical
1332 // links if the body is rebuilt.
1333 bool needToRestoreLinkset = false;
1334 bool needToRestoreVehicle = false;
1335
1336 // Create the correct physical representation for this type of object. 1737 // Create the correct physical representation for this type of object.
1337 // Updates PhysBody and PhysShape with the new information. 1738 // Updates base.PhysBody and base.PhysShape with the new information.
1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1739 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1339 // Returns 'true' if either the body or the shape was changed. 1740 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1340 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1341 { 1741 {
1342 // Called if the current prim body is about to be destroyed. 1742 // Called if the current prim body is about to be destroyed.
1343 // Remove all the physical dependencies on the old body. 1743 // Remove all the physical dependencies on the old body.
1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 1744 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1745 RemoveBodyDependencies();
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1347 }); 1746 });
1348 1747
1349 if (needToRestoreLinkset)
1350 {
1351 // If physical body dependencies were removed, restore them
1352 Linkset.RestoreBodyDependencies(this);
1353 }
1354 if (needToRestoreVehicle)
1355 {
1356 // If physical body dependencies were removed, restore them
1357 _vehicle.RestoreBodyDependencies(this);
1358 }
1359
1360 // Make sure the properties are set on the new object 1748 // Make sure the properties are set on the new object
1361 UpdatePhysicalParameters(); 1749 UpdatePhysicalParameters();
1362 return; 1750 return;
1363 } 1751 }
1364 1752
1365 // The physics engine says that properties have updated. Update same and inform 1753 protected virtual void RemoveBodyDependencies()
1366 // the world that things have changed. 1754 {
1367 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() 1755 VehicleController.RemoveBodyDependencies(this);
1368 enum UpdatedProperties {
1369 Position = 1 << 0,
1370 Rotation = 1 << 1,
1371 Velocity = 1 << 2,
1372 Acceleration = 1 << 3,
1373 RotationalVel = 1 << 4
1374 } 1756 }
1375 1757
1376 const float ROTATION_TOLERANCE = 0.01f; 1758 // The physics engine says that properties have updated. Update same and inform
1377 const float VELOCITY_TOLERANCE = 0.001f; 1759 // the world that things have changed.
1378 const float POSITION_TOLERANCE = 0.05f;
1379 const float ACCELERATION_TOLERANCE = 0.01f;
1380 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1381
1382 public override void UpdateProperties(EntityProperties entprop) 1760 public override void UpdateProperties(EntityProperties entprop)
1383 { 1761 {
1384 /* 1762 TriggerPreUpdatePropertyAction(ref entprop);
1385 UpdatedProperties changed = 0; 1763
1386 // assign to the local variables so the normal set action does not happen 1764 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1387 // if (_position != entprop.Position) 1765 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1388 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) 1766 if (VehicleController.IsActive)
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 { 1767 {
1419 // Only update the position of single objects and linkset roots 1768 entprop.RotationalVelocity = OMV.Vector3.Zero;
1420 if (Linkset.IsRoot(this))
1421 {
1422 base.RequestPhysicsterseUpdate();
1423 }
1424 } 1769 }
1425 */
1426 1770
1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1771 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1428 1772
1429 // Updates only for individual prims and for the root object of a linkset. 1773 // Assign directly to the local variables so the normal set actions do not happen
1430 if (Linkset.IsRoot(this)) 1774 _position = entprop.Position;
1431 { 1775 _orientation = entprop.Rotation;
1432 // Assign directly to the local variables so the normal set action does not happen 1776 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1433 _position = entprop.Position; 1777 // very sensitive to velocity changes.
1434 _orientation = entprop.Rotation; 1778 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold))
1435 _velocity = entprop.Velocity; 1779 _velocity = entprop.Velocity;
1436 _acceleration = entprop.Acceleration; 1780 _acceleration = entprop.Acceleration;
1437 _rotationalVelocity = entprop.RotationalVelocity; 1781 _rotationalVelocity = entprop.RotationalVelocity;
1438 1782
1439 // The sanity check can change the velocity and/or position. 1783 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1440 if (PositionSanityCheck(true))
1441 {
1442 entprop.Position = _position;
1443 entprop.Velocity = _velocity;
1444 }
1445 1784
1446 // remember the current and last set values 1785 // The sanity check can change the velocity and/or position.
1447 LastEntityProperties = CurrentEntityProperties; 1786 if (PositionSanityCheck(true /* inTaintTime */ ))
1448 CurrentEntityProperties = entprop; 1787 {
1788 entprop.Position = _position;
1789 entprop.Velocity = _velocity;
1790 entprop.RotationalVelocity = _rotationalVelocity;
1791 entprop.Acceleration = _acceleration;
1792 }
1449 1793
1450 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; 1794 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1451 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", 1795 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1453 1796
1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG 1797 // remember the current and last set values
1798 LastEntityProperties = CurrentEntityProperties;
1799 CurrentEntityProperties = entprop;
1455 1800
1456 base.RequestPhysicsterseUpdate(); 1801 base.RequestPhysicsterseUpdate();
1457 }
1458 /* 1802 /*
1459 else 1803 else
1460 { 1804 {
@@ -1464,9 +1808,6 @@ public sealed class BSPrim : BSPhysObject
1464 entprop.Acceleration, entprop.RotationalVelocity); 1808 entprop.Acceleration, entprop.RotationalVelocity);
1465 } 1809 }
1466 */ 1810 */
1467
1468 // The linkset implimentation might want to know about this.
1469 Linkset.UpdateProperties(this);
1470 } 1811 }
1471} 1812}
1472} 1813}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
new file mode 100755
index 0000000..f1c3b5c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
@@ -0,0 +1,153 @@
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 copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
28 * are Copyright (c) 2009 Linden Research, Inc and are used under their license
29 * of Creative Commons Attribution-Share Alike 3.0
30 * (http://creativecommons.org/licenses/by-sa/3.0/).
31 */
32
33using System;
34using System.Collections.Generic;
35using System.Reflection;
36using System.Runtime.InteropServices;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Region.Physics.Manager;
40
41using OMV = OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin
44{
45public class BSPrimDisplaced : BSPrim
46{
47 // The purpose of this module is to do any mapping between what the simulator thinks
48 // the prim position and orientation is and what the physical position/orientation.
49 // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
50 // of the prim/linkset. The simulator tracks the location of the prim/linkset by
51 // the location of the root prim. So, if center-of-mass is anywhere but the origin
52 // of the root prim, the physical origin is displaced from the simulator origin.
53 //
54 // This routine works by capturing the Force* setting of position/orientation/... and
55 // adjusting the simulator values (being set) into the physical values.
56 // The conversion is also done in the opposite direction (physical origin -> simulator origin).
57 //
58 // The updateParameter call is also captured and the values from the physics engine
59 // are converted into simulator origin values before being passed to the base
60 // class.
61
62 public virtual OMV.Vector3 PositionDisplacement { get; set; }
63 public virtual OMV.Quaternion OrientationDisplacement { get; set; }
64
65 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
66 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
67 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
68 {
69 ClearDisplacement();
70 }
71
72 public void ClearDisplacement()
73 {
74 PositionDisplacement = OMV.Vector3.Zero;
75 OrientationDisplacement = OMV.Quaternion.Identity;
76 }
77
78 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
79 // A user set value for center-of-mass overrides whatever might be passed in here.
80 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
81 public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement)
82 {
83 Vector3 comDisp;
84 if (UserSetCenterOfMass.HasValue)
85 comDisp = (OMV.Vector3)UserSetCenterOfMass;
86 else
87 comDisp = centerOfMassDisplacement;
88
89 if (comDisp == Vector3.Zero)
90 {
91 // If there is no diplacement. Things get reset.
92 PositionDisplacement = OMV.Vector3.Zero;
93 OrientationDisplacement = OMV.Quaternion.Identity;
94 }
95 else
96 {
97 // Remember the displacement from root as well as the origional rotation of the
98 // new center-of-mass.
99 PositionDisplacement = comDisp;
100 OrientationDisplacement = OMV.Quaternion.Identity;
101 }
102 }
103
104 public override Vector3 ForcePosition
105 {
106 get { return base.ForcePosition; }
107 set
108 {
109 if (PositionDisplacement != OMV.Vector3.Zero)
110 base.ForcePosition = value - (PositionDisplacement * RawOrientation);
111 else
112 base.ForcePosition = value;
113 }
114 }
115
116 public override Quaternion ForceOrientation
117 {
118 get { return base.ForceOrientation; }
119 set
120 {
121 base.ForceOrientation = value;
122 }
123 }
124
125 // TODO: decide if this is the right place for these variables.
126 // Somehow incorporate the optional settability by the user.
127 // Is this used?
128 public override OMV.Vector3 CenterOfMass
129 {
130 get { return RawPosition; }
131 }
132
133 // Is this used?
134 public override OMV.Vector3 GeometricCenter
135 {
136 get { return RawPosition; }
137 }
138
139 public override void UpdateProperties(EntityProperties entprop)
140 {
141 // Undo any center-of-mass displacement that might have been done.
142 if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity)
143 {
144 // Correct for any rotation around the center-of-mass
145 // TODO!!!
146 entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation);
147 // entprop.Rotation = something;
148 }
149
150 base.UpdateProperties(entprop);
151 }
152}
153}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
new file mode 100755
index 0000000..d65d407
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
@@ -0,0 +1,182 @@
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.Linq;
30using System.Text;
31
32using OpenSim.Framework;
33
34using OMV = OpenMetaverse;
35
36namespace OpenSim.Region.Physics.BulletSPlugin
37{
38public class BSPrimLinkable : BSPrimDisplaced
39{
40 public BSLinkset Linkset { get; set; }
41 // The index of this child prim.
42 public int LinksetChildIndex { get; set; }
43
44 public BSLinksetInfo LinksetInfo { get; set; }
45
46 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
47 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
48 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
49 {
50 Linkset = BSLinkset.Factory(PhysicsScene, this);
51
52 PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate()
53 {
54 Linkset.Refresh(this);
55 });
56 }
57
58 public override void Destroy()
59 {
60 Linkset = Linkset.RemoveMeFromLinkset(this);
61 base.Destroy();
62 }
63
64 public override BSPhysicsShapeType PreferredPhysicalShape
65 { get { return Linkset.PreferredPhysicalShape(this); } }
66
67 public override void link(Manager.PhysicsActor obj)
68 {
69 BSPrimLinkable parent = obj as BSPrimLinkable;
70 if (parent != null)
71 {
72 BSPhysObject parentBefore = Linkset.LinksetRoot;
73 int childrenBefore = Linkset.NumberOfChildren;
74
75 Linkset = parent.Linkset.AddMeToLinkset(this);
76
77 DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
78 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
79 }
80 return;
81 }
82
83 public override void delink()
84 {
85 // TODO: decide if this parent checking needs to happen at taint time
86 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
87
88 BSPhysObject parentBefore = Linkset.LinksetRoot;
89 int childrenBefore = Linkset.NumberOfChildren;
90
91 Linkset = Linkset.RemoveMeFromLinkset(this);
92
93 DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
94 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
95 return;
96 }
97
98 // When simulator changes position, this might be moving a child of the linkset.
99 public override OMV.Vector3 Position
100 {
101 get { return base.Position; }
102 set
103 {
104 base.Position = value;
105 PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate()
106 {
107 Linkset.UpdateProperties(UpdatedProperties.Position, this);
108 });
109 }
110 }
111
112 // When simulator changes orientation, this might be moving a child of the linkset.
113 public override OMV.Quaternion Orientation
114 {
115 get { return base.Orientation; }
116 set
117 {
118 base.Orientation = value;
119 PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate()
120 {
121 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
122 });
123 }
124 }
125
126 public override float TotalMass
127 {
128 get { return Linkset.LinksetMass; }
129 }
130
131 public override void UpdatePhysicalParameters()
132 {
133 base.UpdatePhysicalParameters();
134 // Recompute any linkset parameters.
135 // When going from non-physical to physical, this re-enables the constraints that
136 // had been automatically disabled when the mass was set to zero.
137 // For compound based linksets, this enables and disables interactions of the children.
138 if (Linkset != null) // null can happen during initialization
139 Linkset.Refresh(this);
140 }
141
142 protected override void MakeDynamic(bool makeStatic)
143 {
144 base.MakeDynamic(makeStatic);
145 if (makeStatic)
146 Linkset.MakeStatic(this);
147 else
148 Linkset.MakeDynamic(this);
149 }
150
151 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
152 protected override void RemoveBodyDependencies()
153 {
154 Linkset.RemoveBodyDependencies(this);
155 base.RemoveBodyDependencies();
156 }
157
158 public override void UpdateProperties(EntityProperties entprop)
159 {
160 if (Linkset.IsRoot(this))
161 {
162 // Properties are only updated for the roots of a linkset.
163 // TODO: this will have to change when linksets are articulated.
164 base.UpdateProperties(entprop);
165 }
166 // The linkset might like to know about changing locations
167 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
168 }
169
170 public override bool Collide(uint collidingWith, BSPhysObject collidee,
171 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
172 {
173 // prims in the same linkset cannot collide with each other
174 BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
175 if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID))
176 {
177 return false;
178 }
179 return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
180 }
181}
182}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1..e6aefd5 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -26,6 +26,8 @@
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Linq;
30using System.Reflection;
29using System.Runtime.InteropServices; 31using System.Runtime.InteropServices;
30using System.Text; 32using System.Text;
31using System.Threading; 33using System.Threading;
@@ -38,40 +40,22 @@ using Nini.Config;
38using log4net; 40using log4net;
39using OpenMetaverse; 41using OpenMetaverse;
40 42
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 43namespace OpenSim.Region.Physics.BulletSPlugin
64{ 44{
65public sealed class BSScene : PhysicsScene, IPhysicsParameters 45public sealed class BSScene : PhysicsScene, IPhysicsParameters
66{ 46{
67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 47 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
68 private static readonly string LogHeader = "[BULLETS SCENE]"; 48 internal static readonly string LogHeader = "[BULLETS SCENE]";
69 49
70 // The name of the region we're working for. 50 // The name of the region we're working for.
71 public string RegionName { get; private set; } 51 public string RegionName { get; private set; }
72 52
73 public string BulletSimVersion = "?"; 53 public string BulletSimVersion = "?";
74 54
55 // The handle to the underlying managed or unmanaged version of Bullet being used.
56 public string BulletEngineName { get; private set; }
57 public BSAPITemplate PE;
58
75 public Dictionary<uint, BSPhysObject> PhysObjects; 59 public Dictionary<uint, BSPhysObject> PhysObjects;
76 public BSShapeCollection Shapes; 60 public BSShapeCollection Shapes;
77 61
@@ -82,32 +66,29 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
82 // every tick so OpenSim will update its animation. 66 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); 67 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
84 68
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 69 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } } 70 public ILog Logger { get { return m_log; } }
91 71
92 public IMesher mesher; 72 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; } 73 public uint WorldID { get; private set; }
100 public BulletSim World { get; private set; } 74 public BulletWorld World { get; private set; }
101 75
102 // All the constraints that have been allocated in this instance. 76 // All the constraints that have been allocated in this instance.
103 public BSConstraintCollection Constraints { get; private set; } 77 public BSConstraintCollection Constraints { get; private set; }
104 78
105 // Simulation parameters 79 // Simulation parameters
106 private int m_maxSubSteps; 80 internal int m_maxSubSteps;
107 private float m_fixedTimeStep; 81 internal float m_fixedTimeStep;
108 private long m_simulationStep = 0; 82 internal long m_simulationStep = 0;
83 internal float NominalFrameRate { get; set; }
109 public long SimulationStep { get { return m_simulationStep; } } 84 public long SimulationStep { get { return m_simulationStep; } }
110 private 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 PostStepAction 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,15 +159,24 @@ 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 int 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 engineType, string identifier)
203 { 171 {
204 m_initialized = false; 172 m_initialized = false;
205 // we are passed the name of the region we're working for. 173
174 // The name of the region we're working for is passed to us. Keep for identification.
206 RegionName = identifier; 175 RegionName = identifier;
176
177 // Set identifying variables in the PhysicsScene interface.
178 EngineType = engineType;
179 Name = EngineType + "/" + RegionName;
207 } 180 }
208 181
209 public override void Initialise(IMesher meshmerizer, IConfigSource config) 182 public override void Initialise(IMesher meshmerizer, IConfigSource config)
@@ -216,17 +189,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
216 Shapes = new BSShapeCollection(this); 189 Shapes = new BSShapeCollection(this);
217 190
218 // Allocate pinned memory to pass parameters. 191 // Allocate pinned memory to pass parameters.
219 m_params = new ConfigurationParameters[1]; 192 UnmanagedParams = new ConfigurationParameters[1];
220 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
221 193
222 // Set default values for physics parameters plus any overrides from the ini file 194 // Set default values for physics parameters plus any overrides from the ini file
223 GetInitialParameterValues(config); 195 GetInitialParameterValues(config);
224 196
225 // allocate more pinned memory close to the above in an attempt to get the memory all together 197 // Get the connection to the physics engine (could be native or one of many DLLs)
226 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; 198 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 199
231 // Enable very detailed logging. 200 // Enable very detailed logging.
232 // By creating an empty logger when not logging, the log message invocation code 201 // By creating an empty logger when not logging, the log message invocation code
@@ -234,28 +203,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
234 if (m_physicsLoggingEnabled) 203 if (m_physicsLoggingEnabled)
235 { 204 {
236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 205 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
206 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
237 } 207 }
238 else 208 else
239 { 209 {
240 PhysicsLogging = new Logging.LogWriter(); 210 PhysicsLogging = new Logging.LogWriter();
241 } 211 }
242 212
243 // If Debug logging level, enable logging from the unmanaged code 213 // Allocate memory for returning of the updates and collisions from the physics engine
244 m_DebugLogCallbackHandle = null; 214 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
245 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 215 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 216
260 // The bounding box for the simulated world. The origin is 0,0,0 unless we're 217 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
261 // a child in a mega-region. 218 // a child in a mega-region.
@@ -263,18 +220,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
263 // area. It tracks active objects no matter where they are. 220 // area. It tracks active objects no matter where they are.
264 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 221 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
265 222
266 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 223 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 224
272 Constraints = new BSConstraintCollection(World); 225 Constraints = new BSConstraintCollection(World);
273 226
274 TerrainManager = new BSTerrainManager(this); 227 TerrainManager = new BSTerrainManager(this);
275 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 228 TerrainManager.CreateInitialGroundPlaneAndTerrain();
276 229
277 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); 230 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
278 231
279 InTaintTime = false; 232 InTaintTime = false;
280 m_initialized = true; 233 m_initialized = true;
@@ -285,9 +238,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
285 private void GetInitialParameterValues(IConfigSource config) 238 private void GetInitialParameterValues(IConfigSource config)
286 { 239 {
287 ConfigurationParameters parms = new ConfigurationParameters(); 240 ConfigurationParameters parms = new ConfigurationParameters();
288 m_params[0] = parms; 241 UnmanagedParams[0] = parms;
289 242
290 SetParameterDefaultValues(); 243 BSParam.SetParameterDefaultValues(this);
291 244
292 if (config != null) 245 if (config != null)
293 { 246 {
@@ -295,19 +248,34 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
295 IConfig pConfig = config.Configs["BulletSim"]; 248 IConfig pConfig = config.Configs["BulletSim"];
296 if (pConfig != null) 249 if (pConfig != null)
297 { 250 {
298 SetParameterConfigurationValues(pConfig); 251 BSParam.SetParameterConfigurationValues(this, pConfig);
252
253 // There are two Bullet implementations to choose from
254 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
299 255
300 // Very detailed logging for physics debugging 256 // Very detailed logging for physics debugging
257 // TODO: the boolean values can be moved to the normal parameter processing.
301 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 258 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
302 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 259 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
303 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); 260 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
304 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 261 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
262 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
263 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
305 // Very detailed logging for vehicle debugging 264 // Very detailed logging for vehicle debugging
306 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 265 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
266 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
307 267
308 // Do any replacements in the parameters 268 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 269 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
310 } 270 }
271
272 // The material characteristics.
273 BSMaterials.InitializeFromDefaults(Params);
274 if (pConfig != null)
275 {
276 // Let the user add new and interesting material property values.
277 BSMaterials.InitializefromParameters(pConfig);
278 }
311 } 279 }
312 } 280 }
313 281
@@ -326,16 +294,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
326 return ret; 294 return ret;
327 } 295 }
328 296
329 // Called directly from unmanaged code so don't do much 297 // Select the connection to the actual Bullet implementation.
330 private void BulletLogger(string msg) 298 // The main engine selection is the engineName up to the first hypen.
299 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
300 // is passed to the engine to do its special selection, etc.
301 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
331 { 302 {
332 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 303 // For the moment, do a simple switch statement.
333 } 304 // Someday do fancyness with looking up the interfaces in the assembly.
305 BSAPITemplate ret = null;
334 306
335 // Called directly from unmanaged code so don't do much 307 string selectionName = engineName.ToLower();
336 private void BulletLoggerPhysLog(string msg) 308 int hyphenIndex = engineName.IndexOf("-");
337 { 309 if (hyphenIndex > 0)
338 DetailLog("[BULLETS UNMANAGED]:" + msg); 310 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
311
312 switch (selectionName)
313 {
314 case "bulletunmanaged":
315 ret = new BSAPIUnman(engineName, this);
316 break;
317 case "bulletxna":
318 ret = new BSAPIXNA(engineName, this);
319 break;
320 }
321
322 if (ret == null)
323 {
324 m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
325 }
326 else
327 {
328 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
329 }
330
331 return ret;
339 } 332 }
340 333
341 public override void Dispose() 334 public override void Dispose()
@@ -345,8 +338,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
345 // make sure no stepping happens while we're deleting stuff 338 // make sure no stepping happens while we're deleting stuff
346 m_initialized = false; 339 m_initialized = false;
347 340
348 TerrainManager.ReleaseGroundPlaneAndTerrain();
349
350 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) 341 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
351 { 342 {
352 kvp.Value.Destroy(); 343 kvp.Value.Destroy();
@@ -366,8 +357,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
366 Shapes = null; 357 Shapes = null;
367 } 358 }
368 359
360 if (TerrainManager != null)
361 {
362 TerrainManager.ReleaseGroundPlaneAndTerrain();
363 TerrainManager.Dispose();
364 TerrainManager = null;
365 }
366
369 // Anything left in the unmanaged code should be cleaned out 367 // Anything left in the unmanaged code should be cleaned out
370 BulletSimAPI.Shutdown2(World.ptr); 368 PE.Shutdown(World);
371 369
372 // Not logging any more 370 // Not logging any more
373 PhysicsLogging.Close(); 371 PhysicsLogging.Close();
@@ -389,12 +387,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
389 if (!m_initialized) return null; 387 if (!m_initialized) return null;
390 388
391 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 389 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
392 lock (PhysObjects) PhysObjects.Add(localID, actor); 390 lock (PhysObjects)
391 PhysObjects.Add(localID, actor);
393 392
394 // TODO: Remove kludge someday. 393 // TODO: Remove kludge someday.
395 // We must generate a collision for avatars whether they collide or not. 394 // We must generate a collision for avatars whether they collide or not.
396 // This is required by OpenSim to update avatar animations, etc. 395 // This is required by OpenSim to update avatar animations, etc.
397 lock (m_avatars) m_avatars.Add(actor); 396 lock (m_avatars)
397 m_avatars.Add(actor);
398 398
399 return actor; 399 return actor;
400 } 400 }
@@ -410,9 +410,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
410 { 410 {
411 try 411 try
412 { 412 {
413 lock (PhysObjects) PhysObjects.Remove(actor.LocalID); 413 lock (PhysObjects)
414 PhysObjects.Remove(bsactor.LocalID);
414 // Remove kludge someday 415 // Remove kludge someday
415 lock (m_avatars) m_avatars.Remove(bsactor); 416 lock (m_avatars)
417 m_avatars.Remove(bsactor);
416 } 418 }
417 catch (Exception e) 419 catch (Exception e)
418 { 420 {
@@ -421,13 +423,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
421 bsactor.Destroy(); 423 bsactor.Destroy();
422 // bsactor.dispose(); 424 // bsactor.dispose();
423 } 425 }
426 else
427 {
428 m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
429 LogHeader, actor.LocalID, actor.GetType().Name);
430 }
424 } 431 }
425 432
426 public override void RemovePrim(PhysicsActor prim) 433 public override void RemovePrim(PhysicsActor prim)
427 { 434 {
428 if (!m_initialized) return; 435 if (!m_initialized) return;
429 436
430 BSPrim bsprim = prim as BSPrim; 437 BSPhysObject bsprim = prim as BSPhysObject;
431 if (bsprim != null) 438 if (bsprim != null)
432 { 439 {
433 DetailLog("{0},RemovePrim,call", bsprim.LocalID); 440 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
@@ -456,9 +463,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
456 463
457 if (!m_initialized) return null; 464 if (!m_initialized) return null;
458 465
459 DetailLog("{0},AddPrimShape,call", localID); 466 DetailLog("{0},BSScene.AddPrimShape,call", localID);
460 467
461 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 468 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
462 lock (PhysObjects) PhysObjects.Add(localID, prim); 469 lock (PhysObjects) PhysObjects.Add(localID, prim);
463 return prim; 470 return prim;
464 } 471 }
@@ -474,41 +481,56 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
474 // Simulate one timestep 481 // Simulate one timestep
475 public override float Simulate(float timeStep) 482 public override float Simulate(float timeStep)
476 { 483 {
484 // prevent simulation until we've been initialized
485 if (!m_initialized) return 5.0f;
486
487 LastTimeStep = timeStep;
488
477 int updatedEntityCount = 0; 489 int updatedEntityCount = 0;
478 IntPtr updatedEntitiesPtr;
479 int collidersCount = 0; 490 int collidersCount = 0;
480 IntPtr collidersPtr;
481 491
482 int beforeTime = 0; 492 int beforeTime = 0;
483 int simTime = 0; 493 int simTime = 0;
484 494
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 495 // update the prim states while we know the physics engine is not busy
489 int numTaints = _taintOperations.Count; 496 int numTaints = _taintOperations.Count;
497
498 InTaintTime = true; // Only used for debugging so locking is not necessary.
499
490 ProcessTaints(); 500 ProcessTaints();
491 501
492 // Some of the prims operate with special vehicle properties 502 // Some of the physical objects requre individual, pre-step calls
493 ProcessVehicles(timeStep); 503 // (vehicles and avatar movement, in particular)
494 ProcessTaints(); // the vehicles might have added taints 504 TriggerPreStepEvent(timeStep);
505
506 // the prestep actions might have added taints
507 numTaints += _taintOperations.Count;
508 ProcessTaints();
509
510 InTaintTime = false; // Only used for debugging so locking is not necessary.
511
512 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
513 // Only enable this in a limited test world with few objects.
514 if (m_physicsPhysicalDumpEnabled)
515 PE.DumpAllInfo(World);
495 516
496 // step the physical world one interval 517 // step the physical world one interval
497 m_simulationStep++; 518 m_simulationStep++;
498 int numSubSteps = 0; 519 int numSubSteps = 0;
499
500 try 520 try
501 { 521 {
502 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 522 if (PhysicsLogging.Enabled)
503 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 523 beforeTime = Util.EnvironmentTickCount();
504 524
505 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 525 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
506 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
507 526
508 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 527 if (PhysicsLogging.Enabled)
509 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 528 {
510 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 529 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
511 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 530 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
531 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
532 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
533 }
512 } 534 }
513 catch (Exception e) 535 catch (Exception e)
514 { 536 {
@@ -520,9 +542,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
520 collidersCount = 0; 542 collidersCount = 0;
521 } 543 }
522 544
523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 545 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
546 PE.DumpPhysicsStatistics(World);
524 547
525 // Get a value for 'now' so all the collision and update routines don't have to get their own 548 // Get a value for 'now' so all the collision and update routines don't have to get their own.
526 SimulationNowTime = Util.EnvironmentTickCount(); 549 SimulationNowTime = Util.EnvironmentTickCount();
527 550
528 // If there were collisions, process them by sending the event to the prim. 551 // If there were collisions, process them by sending the event to the prim.
@@ -535,8 +558,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
535 uint cB = m_collisionArray[ii].bID; 558 uint cB = m_collisionArray[ii].bID;
536 Vector3 point = m_collisionArray[ii].point; 559 Vector3 point = m_collisionArray[ii].point;
537 Vector3 normal = m_collisionArray[ii].normal; 560 Vector3 normal = m_collisionArray[ii].normal;
538 SendCollision(cA, cB, point, normal, 0.01f); 561 float penetration = m_collisionArray[ii].penetration;
539 SendCollision(cB, cA, point, -normal, 0.01f); 562 SendCollision(cA, cB, point, normal, penetration);
563 SendCollision(cB, cA, point, -normal, penetration);
540 } 564 }
541 } 565 }
542 566
@@ -562,12 +586,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
562 586
563 // Objects that are done colliding are removed from the ObjectsWithCollisions list. 587 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
564 // Not done above because it is inside an iteration of ObjectWithCollisions. 588 // Not done above because it is inside an iteration of ObjectWithCollisions.
589 // This complex collision processing is required to create an empty collision
590 // event call after all real collisions have happened on an object. This enables
591 // the simulator to generate the 'collision end' event.
565 if (ObjectsWithNoMoreCollisions.Count > 0) 592 if (ObjectsWithNoMoreCollisions.Count > 0)
566 { 593 {
567 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) 594 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
568 ObjectsWithCollisions.Remove(po); 595 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear(); 596 ObjectsWithNoMoreCollisions.Clear();
570 } 597 }
598 // Done with collisions.
571 599
572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 600 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
573 if (updatedEntityCount > 0) 601 if (updatedEntityCount > 0)
@@ -583,17 +611,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
583 } 611 }
584 } 612 }
585 613
586 ProcessPostStepTaints(); 614 TriggerPostStepEvent(timeStep);
587 615
588 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. 616 // 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. 617 // Only enable this in a limited test world with few objects.
590 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG 618 if (m_physicsPhysicalDumpEnabled)
619 PE.DumpAllInfo(World);
591 620
592 // The physics engine returns the number of milliseconds it simulated this call. 621 // 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. 622 // 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). 623 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
595 return numSubSteps * m_fixedTimeStep * 1000 * 55; 624 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
596 // return timeStep * 1000 * 55;
597 } 625 }
598 626
599 // Something has collided 627 // Something has collided
@@ -639,12 +667,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
639 667
640 public override void SetWaterLevel(float baseheight) 668 public override void SetWaterLevel(float baseheight)
641 { 669 {
642 m_waterLevel = baseheight; 670 SimpleWaterLevel = baseheight;
643 }
644 // Someday....
645 public float GetWaterLevelAtXYZ(Vector3 loc)
646 {
647 return m_waterLevel;
648 } 671 }
649 672
650 public override void DeleteTerrain() 673 public override void DeleteTerrain()
@@ -675,12 +698,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
675 698
676 public override Dictionary<uint, float> GetTopColliders() 699 public override Dictionary<uint, float> GetTopColliders()
677 { 700 {
678 return new Dictionary<uint, float>(); 701 Dictionary<uint, float> topColliders;
702
703 lock (PhysObjects)
704 {
705 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
706 {
707 kvp.Value.ComputeCollisionScore();
708 }
709
710 List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values);
711 orderedPrims.OrderByDescending(p => p.CollisionScore);
712 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
713 }
714
715 return topColliders;
679 } 716 }
680 717
681 public override bool IsThreaded { get { return false; } } 718 public override bool IsThreaded { get { return false; } }
682 719
683 #region Taints 720 #region Taints
721 // The simulation execution order is:
722 // Simulate()
723 // DoOneTimeTaints
724 // TriggerPreStepEvent
725 // DoOneTimeTaints
726 // Step()
727 // ProcessAndSendToSimulatorCollisions
728 // ProcessAndSendToSimulatorPropertyUpdates
729 // TriggerPostStepEvent
684 730
685 // Calls to the PhysicsActors can't directly call into the physics engine 731 // 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. 732 // because it might be busy. We delay changes to a known time.
@@ -707,58 +753,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
707 TaintedObject(ident, callback); 753 TaintedObject(ident, callback);
708 } 754 }
709 755
756 private void TriggerPreStepEvent(float timeStep)
757 {
758 PreStepAction actions = BeforeStep;
759 if (actions != null)
760 actions(timeStep);
761
762 }
763
764 private void TriggerPostStepEvent(float timeStep)
765 {
766 PostStepAction actions = AfterStep;
767 if (actions != null)
768 actions(timeStep);
769
770 }
771
710 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 772 // 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 773 // 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. 774 // here just before the physics engine is called to step the simulation.
713 public void ProcessTaints() 775 public void ProcessTaints()
714 { 776 {
715 InTaintTime = true; // Only used for debugging so locking is not necessary.
716 ProcessRegularTaints(); 777 ProcessRegularTaints();
717 ProcessPostTaintTaints(); 778 ProcessPostTaintTaints();
718 InTaintTime = false;
719 } 779 }
720 780
721 private void ProcessRegularTaints() 781 private void ProcessRegularTaints()
722 { 782 {
723 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process 783 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
724 { 784 {
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 785 // swizzle a new list into the list location so we can process what's there
763 List<TaintCallbackEntry> oldList; 786 List<TaintCallbackEntry> oldList;
764 lock (_taintLock) 787 lock (_taintLock)
@@ -797,6 +820,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
797 return; 820 return;
798 } 821 }
799 822
823 // Taints that happen after the normal taint processing but before the simulation step.
800 private void ProcessPostTaintTaints() 824 private void ProcessPostTaintTaints()
801 { 825 {
802 if (_postTaintOperations.Count > 0) 826 if (_postTaintOperations.Count > 0)
@@ -824,45 +848,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
824 } 848 }
825 } 849 }
826 850
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. 851 // Only used for debugging. Does not change state of anything so locking is not necessary.
867 public bool AssertInTaintTime(string whereFrom) 852 public bool AssertInTaintTime(string whereFrom)
868 { 853 {
@@ -870,517 +855,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
870 { 855 {
871 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); 856 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); 857 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. 858 // Util.PrintCallStack(DetailLog);
874 } 859 }
875 return InTaintTime; 860 return InTaintTime;
876 } 861 }
877 862
878 #endregion // Taints 863 #endregion // Taints
879 864
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
930
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 865 #region IPhysicsParameters
1379 // Get the list of parameters this physics engine supports 866 // Get the list of parameters this physics engine supports
1380 public PhysParameterEntry[] GetParameterList() 867 public PhysParameterEntry[] GetParameterList()
1381 { 868 {
1382 BuildParameterTable(); 869 BSParam.BuildParameterTable();
1383 return SettableParameters; 870 return BSParam.SettableParameters;
1384 } 871 }
1385 872
1386 // Set parameter on a specific or all instances. 873 // Set parameter on a specific or all instances.
@@ -1389,63 +876,65 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1389 // will use the next time since it's pinned and shared memory. 876 // will use the next time since it's pinned and shared memory.
1390 // Some of the values require calling into the physics engine to get the new 877 // Some of the values require calling into the physics engine to get the new
1391 // value activated ('terrainFriction' for instance). 878 // value activated ('terrainFriction' for instance).
1392 public bool SetPhysicsParameter(string parm, float val, uint localID) 879 public bool SetPhysicsParameter(string parm, string val, uint localID)
1393 { 880 {
1394 bool ret = false; 881 bool ret = false;
1395 ParameterDefn theParam; 882
1396 if (TryGetParameter(parm, out theParam)) 883 BSParam.ParameterDefnBase theParam;
884 if (BSParam.TryGetParameter(parm, out theParam))
1397 { 885 {
1398 theParam.setter(this, parm, localID, val); 886 // Set the value in the C# code
887 theParam.SetValue(this, val);
888
889 // Optionally set the parameter in the unmanaged code
890 if (theParam.HasSetOnObject)
891 {
892 // update all the localIDs specified
893 // If the local ID is APPLY_TO_NONE, just change the default value
894 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
895 // If the localID is a specific object, apply the parameter change to only that object
896 List<uint> objectIDs = new List<uint>();
897 switch (localID)
898 {
899 case PhysParameterEntry.APPLY_TO_NONE:
900 // This will cause a call into the physical world if some operation is specified (SetOnObject).
901 objectIDs.Add(TERRAIN_ID);
902 TaintedUpdateParameter(parm, objectIDs, val);
903 break;
904 case PhysParameterEntry.APPLY_TO_ALL:
905 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
906 TaintedUpdateParameter(parm, objectIDs, val);
907 break;
908 default:
909 // setting only one localID
910 objectIDs.Add(localID);
911 TaintedUpdateParameter(parm, objectIDs, val);
912 break;
913 }
914 }
915
1399 ret = true; 916 ret = true;
1400 } 917 }
1401 return ret; 918 return ret;
1402 } 919 }
1403 920
1404 // update all the localIDs specified
1405 // 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
1407 // 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)
1409 {
1410 List<uint> objectIDs = new List<uint>();
1411 switch (localID)
1412 {
1413 case PhysParameterEntry.APPLY_TO_NONE:
1414 defaultLoc = val; // setting only the default value
1415 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1416 objectIDs.Add(TERRAIN_ID);
1417 TaintedUpdateParameter(parm, objectIDs, val);
1418 break;
1419 case PhysParameterEntry.APPLY_TO_ALL:
1420 defaultLoc = val; // setting ALL also sets the default value
1421 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1422 TaintedUpdateParameter(parm, objectIDs, val);
1423 break;
1424 default:
1425 // setting only one localID
1426 objectIDs.Add(localID);
1427 TaintedUpdateParameter(parm, objectIDs, val);
1428 break;
1429 }
1430 }
1431
1432 // schedule the actual updating of the paramter to when the phys engine is not busy 921 // schedule the actual updating of the paramter to when the phys engine is not busy
1433 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) 922 private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val)
1434 { 923 {
1435 float xval = val; 924 string xval = val;
1436 List<uint> xlIDs = lIDs; 925 List<uint> xlIDs = lIDs;
1437 string xparm = parm; 926 string xparm = parm;
1438 TaintedObject("BSScene.UpdateParameterSet", delegate() { 927 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1439 ParameterDefn thisParam; 928 BSParam.ParameterDefnBase thisParam;
1440 if (TryGetParameter(xparm, out thisParam)) 929 if (BSParam.TryGetParameter(xparm, out thisParam))
1441 { 930 {
1442 if (thisParam.onObject != null) 931 if (thisParam.HasSetOnObject)
1443 { 932 {
1444 foreach (uint lID in xlIDs) 933 foreach (uint lID in xlIDs)
1445 { 934 {
1446 BSPhysObject theObject = null; 935 BSPhysObject theObject = null;
1447 PhysObjects.TryGetValue(lID, out theObject); 936 if (PhysObjects.TryGetValue(lID, out theObject))
1448 thisParam.onObject(this, theObject, xval); 937 thisParam.SetOnObject(this, theObject);
1449 } 938 }
1450 } 939 }
1451 } 940 }
@@ -1454,14 +943,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1454 943
1455 // Get parameter. 944 // Get parameter.
1456 // Return 'false' if not able to get the parameter. 945 // Return 'false' if not able to get the parameter.
1457 public bool GetPhysicsParameter(string parm, out float value) 946 public bool GetPhysicsParameter(string parm, out string value)
1458 { 947 {
1459 float val = 0f; 948 string val = String.Empty;
1460 bool ret = false; 949 bool ret = false;
1461 ParameterDefn theParam; 950 BSParam.ParameterDefnBase theParam;
1462 if (TryGetParameter(parm, out theParam)) 951 if (BSParam.TryGetParameter(parm, out theParam))
1463 { 952 {
1464 val = theParam.getter(this); 953 val = theParam.GetValue(this);
1465 ret = true; 954 ret = true;
1466 } 955 }
1467 value = val; 956 value = val;
@@ -1470,24 +959,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1470 959
1471 #endregion IPhysicsParameters 960 #endregion IPhysicsParameters
1472 961
1473 #endregion Runtime settable parameters
1474
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. 962 // Invoke the detailed logger and output something if it's enabled.
1486 public void DetailLog(string msg, params Object[] args) 963 public void DetailLog(string msg, params Object[] args)
1487 { 964 {
1488 PhysicsLogging.Write(msg, args); 965 PhysicsLogging.Write(msg, args);
1489 // Add the Flush() if debugging crashes. Gets all the messages written out. 966 // Add the Flush() if debugging crashes. Gets all the messages written out.
1490 // PhysicsLogging.Flush(); 967 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
1491 } 968 }
1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 969 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1493 public const string DetailLogZero = "0000000000"; 970 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..220fbbc 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");
@@ -109,8 +116,7 @@ public sealed class BSShapeCollection : IDisposable
109 // rebuild the body around it. 116 // rebuild the body around it.
110 // Updates prim.BSBody with information/pointers to requested body 117 // Updates prim.BSBody with information/pointers to requested body
111 // Returns 'true' if BSBody was changed. 118 // Returns 'true' if BSBody was changed.
112 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback);
113 prim.PhysShape, bodyCallback);
114 ret = newGeom || newBody; 120 ret = newGeom || newBody;
115 } 121 }
116 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", 122 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
@@ -119,51 +125,52 @@ public sealed class BSShapeCollection : IDisposable
119 return ret; 125 return ret;
120 } 126 }
121 127
128 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
129 {
130 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
131 }
132
122 // Track another user of a body. 133 // Track another user of a body.
123 // We presume the caller has allocated the body. 134 // 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. 135 // Bodies only have one user so the body is just put into the world if not already there.
125 public void ReferenceBody(BulletBody body, bool inTaintTime) 136 private void ReferenceBody(BulletBody body)
126 { 137 {
127 lock (m_collectionActivityLock) 138 lock (m_collectionActivityLock)
128 { 139 {
129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); 140 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() 141 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
131 { 142 {
132 if (!BulletSimAPI.IsInWorld2(body.ptr)) 143 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
133 { 144 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 145 }
135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
136 }
137 });
138 } 146 }
139 } 147 }
140 148
141 // Release the usage of a body. 149 // Release the usage of a body.
142 // Called when releasing use of a BSBody. BSShape is handled separately. 150 // Called when releasing use of a BSBody. BSShape is handled separately.
143 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) 151 // Called in taint time.
152 public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback )
144 { 153 {
145 if (body.ptr == IntPtr.Zero) 154 if (!body.HasPhysicalBody)
146 return; 155 return;
147 156
157 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
158
148 lock (m_collectionActivityLock) 159 lock (m_collectionActivityLock)
149 { 160 {
150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() 161 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
151 { 162 // If the caller needs to know the old body is going away, pass the event up.
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", 163 if (bodyCallback != null) bodyCallback(body);
153 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body);
156 164
157 if (BulletSimAPI.IsInWorld2(body.ptr)) 165 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
158 { 166 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 167 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); 168 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 } 169 }
162 170
163 // Zero any reference to the shape so it is not freed when the body is deleted. 171 // 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); 172 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 173 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
166 });
167 } 174 }
168 } 175 }
169 176
@@ -184,17 +191,17 @@ public sealed class BSShapeCollection : IDisposable
184 { 191 {
185 // There is an existing instance of this mesh. 192 // There is an existing instance of this mesh.
186 meshDesc.referenceCount++; 193 meshDesc.referenceCount++;
187 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", 194 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
188 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 195 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
189 } 196 }
190 else 197 else
191 { 198 {
192 // This is a new reference to a mesh 199 // This is a new reference to a mesh
193 meshDesc.ptr = shape.ptr; 200 meshDesc.shape = shape.Clone();
194 meshDesc.shapeKey = shape.shapeKey; 201 meshDesc.shapeKey = shape.shapeKey;
195 // We keep a reference to the underlying IMesh data so a hull can be built 202 // We keep a reference to the underlying IMesh data so a hull can be built
196 meshDesc.referenceCount = 1; 203 meshDesc.referenceCount = 1;
197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 204 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
198 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 205 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
199 ret = true; 206 ret = true;
200 } 207 }
@@ -207,16 +214,16 @@ public sealed class BSShapeCollection : IDisposable
207 { 214 {
208 // There is an existing instance of this hull. 215 // There is an existing instance of this hull.
209 hullDesc.referenceCount++; 216 hullDesc.referenceCount++;
210 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", 217 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 218 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
212 } 219 }
213 else 220 else
214 { 221 {
215 // This is a new reference to a hull 222 // This is a new reference to a hull
216 hullDesc.ptr = shape.ptr; 223 hullDesc.shape = shape.Clone();
217 hullDesc.shapeKey = shape.shapeKey; 224 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 225 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 226 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 227 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true; 228 ret = true;
222 229
@@ -234,44 +241,43 @@ public sealed class BSShapeCollection : IDisposable
234 } 241 }
235 242
236 // Release the usage of a shape. 243 // Release the usage of a shape.
237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 244 public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback)
238 { 245 {
239 if (shape.ptr == IntPtr.Zero) 246 if (!shape.HasPhysicalShape)
240 return; 247 return;
241 248
242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() 249 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape");
250
251 if (shape.HasPhysicalShape)
243 { 252 {
244 if (shape.ptr != IntPtr.Zero) 253 if (shape.isNativeShape)
245 { 254 {
246 if (shape.isNativeShape) 255 // Native shapes are not tracked and are released immediately
247 { 256 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}",
248 // Native shapes are not tracked and are released immediately 257 BSScene.DetailLogZero, shape.AddrString);
249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 258 if (shapeCallback != null) shapeCallback(shape);
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 259 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
251 if (shapeCallback != null) shapeCallback(shape); 260 }
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 261 else
253 } 262 {
254 else 263 switch (shape.type)
255 { 264 {
256 switch (shape.type) 265 case BSPhysicsShapeType.SHAPE_HULL:
257 { 266 DereferenceHull(shape, shapeCallback);
258 case BSPhysicsShapeType.SHAPE_HULL: 267 break;
259 DereferenceHull(shape, shapeCallback); 268 case BSPhysicsShapeType.SHAPE_MESH:
260 break; 269 DereferenceMesh(shape, shapeCallback);
261 case BSPhysicsShapeType.SHAPE_MESH: 270 break;
262 DereferenceMesh(shape, shapeCallback); 271 case BSPhysicsShapeType.SHAPE_COMPOUND:
263 break; 272 DereferenceCompound(shape, shapeCallback);
264 case BSPhysicsShapeType.SHAPE_COMPOUND: 273 break;
265 DereferenceCompound(shape, shapeCallback); 274 case BSPhysicsShapeType.SHAPE_UNKNOWN:
266 break; 275 break;
267 case BSPhysicsShapeType.SHAPE_UNKNOWN: 276 default:
268 break; 277 break;
269 default:
270 break;
271 }
272 } 278 }
273 } 279 }
274 }); 280 }
275 } 281 }
276 282
277 // Count down the reference count for a mesh shape 283 // Count down the reference count for a mesh shape
@@ -286,7 +292,7 @@ public sealed class BSShapeCollection : IDisposable
286 if (shapeCallback != null) shapeCallback(shape); 292 if (shapeCallback != null) shapeCallback(shape);
287 meshDesc.lastReferenced = System.DateTime.Now; 293 meshDesc.lastReferenced = System.DateTime.Now;
288 Meshes[shape.shapeKey] = meshDesc; 294 Meshes[shape.shapeKey] = meshDesc;
289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", 295 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
290 BSScene.DetailLogZero, shape, meshDesc.referenceCount); 296 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
291 297
292 } 298 }
@@ -307,7 +313,7 @@ public sealed class BSShapeCollection : IDisposable
307 313
308 hullDesc.lastReferenced = System.DateTime.Now; 314 hullDesc.lastReferenced = System.DateTime.Now;
309 Hulls[shape.shapeKey] = hullDesc; 315 Hulls[shape.shapeKey] = hullDesc;
310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", 316 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
311 BSScene.DetailLogZero, shape, hullDesc.referenceCount); 317 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 } 318 }
313 } 319 }
@@ -320,57 +326,56 @@ public sealed class BSShapeCollection : IDisposable
320 // Called at taint-time. 326 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) 327 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 { 328 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr)) 329 if (!PhysicsScene.PE.IsCompound(shape))
324 { 330 {
325 // Failed the sanity check!! 331 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", 332 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")); 333 LogHeader, shape.type, shape.AddrString);
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", 334 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); 335 BSScene.DetailLogZero, shape.type, shape.AddrString);
330 return; 336 return;
331 } 337 }
332 338
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 339 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); 340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335 341
336 for (int ii = numChildren - 1; ii >= 0; ii--) 342 for (int ii = numChildren - 1; ii >= 0; ii--)
337 { 343 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); 344 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
339 DereferenceAnonCollisionShape(childShape); 345 DereferenceAnonCollisionShape(childShape);
340 } 346 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 347 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
342 } 348 }
343 349
344 // Sometimes we have a pointer to a collision shape but don't know what type it is. 350 // 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. 351 // Figure out type and call the correct dereference routine.
346 // Called at taint-time. 352 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape) 353 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
348 { 354 {
349 MeshDesc meshDesc; 355 MeshDesc meshDesc;
350 HullDesc hullDesc; 356 HullDesc hullDesc;
351 357
352 BulletShape shapeInfo = new BulletShape(cShape); 358 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 { 359 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; 360 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey; 361 shapeInfo.shapeKey = meshDesc.shapeKey;
357 } 362 }
358 else 363 else
359 { 364 {
360 if (TryGetHullByPtr(cShape, out hullDesc)) 365 if (TryGetHullByPtr(shapeInfo, out hullDesc))
361 { 366 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; 367 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey; 368 shapeInfo.shapeKey = hullDesc.shapeKey;
364 } 369 }
365 else 370 else
366 { 371 {
367 if (BulletSimAPI.IsCompound2(cShape)) 372 if (PhysicsScene.PE.IsCompound(shapeInfo))
368 { 373 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; 374 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 } 375 }
371 else 376 else
372 { 377 {
373 if (BulletSimAPI.IsNativeShape2(cShape)) 378 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
374 { 379 {
375 shapeInfo.isNativeShape = true; 380 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) 381 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
@@ -379,16 +384,16 @@ public sealed class BSShapeCollection : IDisposable
379 } 384 }
380 } 385 }
381 386
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 387 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 388
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) 389 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 390 {
386 DereferenceShape(shapeInfo, true, null); 391 DereferenceShape(shapeInfo, null);
387 } 392 }
388 else 393 else
389 { 394 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", 395 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); 396 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
392 } 397 }
393 } 398 }
394 399
@@ -408,19 +413,18 @@ public sealed class BSShapeCollection : IDisposable
408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 413 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 { 414 {
410 // an avatar capsule is close to a native shape (it is not shared) 415 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, 416 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
412 FixedShapeKey.KEY_CAPSULE, shapeCallback); 417 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; 418 ret = true;
415 haveShape = true; 419 haveShape = true;
416 } 420 }
417 421
418 // Compound shapes are handled special as they are rebuilt from scratch. 422 // 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. 423 // 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) 424 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 425 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 426 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 427 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true; 428 haveShape = true;
425 } 429 }
426 430
@@ -432,8 +436,9 @@ public sealed class BSShapeCollection : IDisposable
432 return ret; 436 return ret;
433 } 437 }
434 438
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. 439 // Create a mesh, hull or native shape.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 440 // Return 'true' if the prim's shape was changed.
441 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 { 442 {
438 bool ret = false; 443 bool ret = false;
439 bool haveShape = false; 444 bool haveShape = false;
@@ -442,46 +447,48 @@ public sealed class BSShapeCollection : IDisposable
442 447
443 // If the prim attributes are simple, this could be a simple Bullet native shape 448 // If the prim attributes are simple, this could be a simple Bullet native shape
444 if (!haveShape 449 if (!haveShape
445 && pbs != null
446 && nativeShapePossible 450 && nativeShapePossible
447 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 451 && pbs != null
448 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 452 && !pbs.SculptEntry
449 && pbs.ProfileHollow == 0 453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) )
450 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 454 {
451 && pbs.PathBegin == 0 && pbs.PathEnd == 0 455 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
452 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 456 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 457 if (prim.PhysShape.HasPhysicalShape)
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 458 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
455 { 459
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 460 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
461 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
462
463 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 464 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 465 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 { 466 {
460 haveShape = true; 467 haveShape = true;
461 if (forceRebuild 468 if (forceRebuild
462 || prim.Scale != prim.Size 469 || prim.Scale != scaleOfExistingShape
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 470 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 471 )
465 { 472 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 473 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 474 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 475 }
476 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
477 prim.LocalID, forceRebuild, ret, prim.PhysShape);
471 } 478 }
472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 479 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
473 { 480 {
474 haveShape = true; 481 haveShape = true;
475 if (forceRebuild 482 if (forceRebuild
476 || prim.Scale != prim.Size 483 || prim.Scale != scaleOfExistingShape
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 484 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 485 )
479 { 486 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 487 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 488 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 489 }
490 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
491 prim.LocalID, forceRebuild, ret, prim.PhysShape);
485 } 492 }
486 } 493 }
487 494
@@ -494,23 +501,36 @@ public sealed class BSShapeCollection : IDisposable
494 return ret; 501 return ret;
495 } 502 }
496 503
504 // return 'true' if this shape description does not include any cutting or twisting.
505 private bool PrimHasNoCuts(PrimitiveBaseShape pbs)
506 {
507 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
508 && pbs.ProfileHollow == 0
509 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
510 && pbs.PathBegin == 0 && pbs.PathEnd == 0
511 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
512 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
513 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
514 }
515
516 // return 'true' if the prim's shape was changed.
497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
498 { 518 {
499 519
500 bool ret = false; 520 bool ret = false;
501 // Note that if it's a native shape, the check for physical/non-physical is not 521 // Note that if it's a native shape, the check for physical/non-physical is not
502 // made. Native shapes work in either case. 522 // made. Native shapes work in either case.
503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
504 { 524 {
505 // Update prim.BSShape to reference a hull of this shape. 525 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 526 ret = GetReferenceToHull(prim, shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 529 }
510 else 530 else
511 { 531 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 532 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 533 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 534 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 535 }
516 return ret; 536 return ret;
@@ -523,14 +543,15 @@ public sealed class BSShapeCollection : IDisposable
523 ShapeDestructionCallback shapeCallback) 543 ShapeDestructionCallback shapeCallback)
524 { 544 {
525 // release any previous shape 545 // release any previous shape
526 DereferenceShape(prim.PhysShape, true, shapeCallback); 546 DereferenceShape(prim.PhysShape, shapeCallback);
527 547
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 548 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 549
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 550 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 551 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 552 prim.LocalID, newShape, prim.Scale);
533 553
554 // native shapes are scaled by Bullet
534 prim.PhysShape = newShape; 555 prim.PhysShape = newShape;
535 return true; 556 return true;
536 } 557 }
@@ -550,20 +571,17 @@ public sealed class BSShapeCollection : IDisposable
550 571
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 572 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
552 { 573 {
553 // The proper scale has been calculated in the prim. 574
554 newShape = new BulletShape( 575 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 576 if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 577 }
559 else 578 else
560 { 579 {
561 // Native shapes are scaled in Bullet so set the scaling to the size 580 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size; 581 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
563 nativeShapeData.Scale = prim.Scale; 582
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 } 583 }
566 if (newShape.ptr == IntPtr.Zero) 584 if (!newShape.HasPhysicalShape)
567 { 585 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 586 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType); 587 LogHeader, prim.LocalID, shapeType);
@@ -580,7 +598,7 @@ public sealed class BSShapeCollection : IDisposable
580 // Called at taint-time! 598 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 599 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 { 600 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero); 601 BulletShape newShape = new BulletShape();
584 602
585 float lod; 603 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 604 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -589,62 +607,96 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 607 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 608 return false;
591 609
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 610 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 611 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
594 612
595 // Since we're recreating new, get rid of the reference to the previous shape 613 // Since we're recreating new, get rid of the reference to the previous shape
596 DereferenceShape(prim.PhysShape, true, shapeCallback); 614 DereferenceShape(prim.PhysShape, shapeCallback);
597 615
598 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); 616 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
599 // Take evasive action if the mesh was not constructed. 617 // Take evasive action if the mesh was not constructed.
600 newShape = VerifyMeshCreated(newShape, prim); 618 newShape = VerifyMeshCreated(newShape, prim);
601 619
602 ReferenceShape(newShape); 620 ReferenceShape(newShape);
603 621
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape; 622 prim.PhysShape = newShape;
607 623
608 return true; // 'true' means a new shape has been added to this prim 624 return true; // 'true' means a new shape has been added to this prim
609 } 625 }
610 626
611 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 627 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
612 { 628 {
613 IMesh meshData = null; 629 BulletShape newShape = new BulletShape();
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 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 640 true,
641 false, // say it is not physical so a bounding box is not built
642 false, // do not cache the mesh and do not use previously built versions
643 false // It's NOT for ODE
644 );
625 645
626 if (meshData != null) 646 if (meshData != null)
627 { 647 {
648
628 int[] indices = meshData.getIndexListAsInt(); 649 int[] indices = meshData.getIndexListAsInt();
629 List<OMV.Vector3> vertices = meshData.getVertexList(); 650 int realIndicesIndex = indices.Length;
651 float[] verticesAsFloats = meshData.getVertexListAsFloat();
630 652
631 float[] verticesAsFloats = new float[vertices.Count * 3]; 653 if (BSParam.ShouldRemoveZeroWidthTriangles)
632 int vi = 0;
633 foreach (OMV.Vector3 vv in vertices)
634 { 654 {
635 verticesAsFloats[vi++] = vv.X; 655 // Remove degenerate triangles. These are triangles with two of the vertices
636 verticesAsFloats[vi++] = vv.Y; 656 // are the same. This is complicated by the problem that vertices are not
637 verticesAsFloats[vi++] = vv.Z; 657 // made unique in sculpties so we have to compare the values in the vertex.
658 realIndicesIndex = 0;
659 for (int tri = 0; tri < indices.Length; tri += 3)
660 {
661 // Compute displacements into vertex array for each vertex of the triangle
662 int v1 = indices[tri + 0] * 3;
663 int v2 = indices[tri + 1] * 3;
664 int v3 = indices[tri + 2] * 3;
665 // Check to see if any two of the vertices are the same
666 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
667 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
668 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
669 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
670 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
671 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
672 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
673 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
674 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
675 )
676 {
677 // None of the vertices of the triangles are the same. This is a good triangle;
678 indices[realIndicesIndex + 0] = indices[tri + 0];
679 indices[realIndicesIndex + 1] = indices[tri + 1];
680 indices[realIndicesIndex + 2] = indices[tri + 2];
681 realIndicesIndex += 3;
682 }
683 }
638 } 684 }
685 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
686 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
639 687
640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 688 if (realIndicesIndex != 0)
641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 689 {
642 690 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 691 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 692 }
693 else
694 {
695 PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
696 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
697 }
645 } 698 }
646 } 699 }
647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
648 newShape.shapeKey = newMeshKey; 700 newShape.shapeKey = newMeshKey;
649 701
650 return newShape; 702 return newShape;
@@ -652,6 +704,7 @@ public sealed class BSShapeCollection : IDisposable
652 704
653 // See that hull shape exists in the physical world and update prim.BSShape. 705 // See that hull shape exists in the physical world and update prim.BSShape.
654 // We could be creating the hull because scale changed or whatever. 706 // We could be creating the hull because scale changed or whatever.
707 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
655 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 708 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
656 { 709 {
657 BulletShape newShape; 710 BulletShape newShape;
@@ -663,19 +716,18 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 716 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 717 return false;
665 718
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 719 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 720 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 721
669 // Remove usage of the previous shape. 722 // Remove usage of the previous shape.
670 DereferenceShape(prim.PhysShape, true, shapeCallback); 723 DereferenceShape(prim.PhysShape, shapeCallback);
671 724
672 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); 725 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
726 // It might not have been created if we're waiting for an asset.
673 newShape = VerifyMeshCreated(newShape, prim); 727 newShape = VerifyMeshCreated(newShape, prim);
674 728
675 ReferenceShape(newShape); 729 ReferenceShape(newShape);
676 730
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape; 731 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim 732 return true; // 'true' means a new shape has been added to this prim
681 } 733 }
@@ -684,18 +736,20 @@ public sealed class BSShapeCollection : IDisposable
684 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 736 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
685 { 737 {
686 738
739 BulletShape newShape = new BulletShape();
687 IntPtr hullPtr = IntPtr.Zero; 740 IntPtr hullPtr = IntPtr.Zero;
741
688 HullDesc hullDesc; 742 HullDesc hullDesc;
689 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 743 if (Hulls.TryGetValue(newHullKey, out hullDesc))
690 { 744 {
691 // If the hull shape already is created, just use it. 745 // If the hull shape already has been created, just use the one shared instance.
692 hullPtr = hullDesc.ptr; 746 newShape = hullDesc.shape.Clone();
693 } 747 }
694 else 748 else
695 { 749 {
696 // Build a new hull in the physical world 750 // 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 751 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 752 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
699 if (meshData != null) 753 if (meshData != null)
700 { 754 {
701 755
@@ -714,15 +768,35 @@ public sealed class BSShapeCollection : IDisposable
714 convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); 768 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
715 } 769 }
716 770
771 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
772 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
773 {
774 // Simple primitive shapes we know are convex so they are better implemented with
775 // fewer hulls.
776 // Check for simple shape (prim without cuts) and reduce split parameter if so.
777 if (PrimHasNoCuts(pbs))
778 {
779 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
780 }
781 }
782
717 // setup and do convex hull conversion 783 // setup and do convex hull conversion
718 m_hulls = new List<ConvexResult>(); 784 m_hulls = new List<ConvexResult>();
719 DecompDesc dcomp = new DecompDesc(); 785 DecompDesc dcomp = new DecompDesc();
720 dcomp.mIndices = convIndices; 786 dcomp.mIndices = convIndices;
721 dcomp.mVertices = convVertices; 787 dcomp.mVertices = convVertices;
788 dcomp.mDepth = maxDepthSplit;
789 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
790 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
791 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
792 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
722 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); 793 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
723 // create the hull into the _hulls variable 794 // create the hull into the _hulls variable
724 convexBuilder.process(dcomp); 795 convexBuilder.process(dcomp);
725 796
797 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
798 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
799
726 // Convert the vertices and indices for passing to unmanaged. 800 // Convert the vertices and indices for passing to unmanaged.
727 // The hull information is passed as a large floating point array. 801 // The hull information is passed as a large floating point array.
728 // The format is: 802 // The format is:
@@ -777,14 +851,13 @@ public sealed class BSShapeCollection : IDisposable
777 } 851 }
778 } 852 }
779 // create the hull data structure in Bullet 853 // create the hull data structure in Bullet
780 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); 854 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
781 } 855 }
782 } 856 }
783 857
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey; 858 newShape.shapeKey = newHullKey;
786 859
787 return newShape; // 'true' means a new shape has been added to this prim 860 return newShape;
788 } 861 }
789 862
790 // Callback from convex hull creater with a newly created hull. 863 // Callback from convex hull creater with a newly created hull.
@@ -803,13 +876,12 @@ 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. 876 // 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); 877 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805 878
806 BulletShape cShape = new BulletShape( 879 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
808 880
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 881 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 882 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 883 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 884 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 885 prim.LocalID, cShape, prim.PhysShape);
814 886
815 prim.PhysShape = cShape; 887 prim.PhysShape = cShape;
@@ -822,14 +894,19 @@ public sealed class BSShapeCollection : IDisposable
822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) 894 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
823 { 895 {
824 // level of detail based on size and type of the object 896 // level of detail based on size and type of the object
825 float lod = PhysicsScene.MeshLOD; 897 float lod = BSParam.MeshLOD;
898
899 // prims with curvy internal cuts need higher lod
900 if (pbs.HollowShape == HollowShape.Circle)
901 lod = BSParam.MeshCircularLOD;
902
826 if (pbs.SculptEntry) 903 if (pbs.SculptEntry)
827 lod = PhysicsScene.SculptLOD; 904 lod = BSParam.SculptLOD;
828 905
829 // Mega prims usually get more detail because one can interact with shape approximations at this size. 906 // 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)); 907 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 908 if (maxAxis > BSParam.MeshMegaPrimThreshold)
832 lod = PhysicsScene.MeshMegaPrimLOD; 909 lod = BSParam.MeshMegaPrimLOD;
833 910
834 retLod = lod; 911 retLod = lod;
835 return pbs.GetMeshKey(size, lod); 912 return pbs.GetMeshKey(size, lod);
@@ -851,51 +928,88 @@ public sealed class BSShapeCollection : IDisposable
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 928 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 { 929 {
853 // If the shape was successfully created, nothing more to do 930 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero) 931 if (newShape.HasPhysicalShape)
855 return newShape; 932 return newShape;
856 933
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 934 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
858 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) 935 // fetched but we end up here again, the meshing of the asset must have failed.
936 // Prevent trying to keep fetching the mesh by declaring failure.
937 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
859 { 938 {
860 prim.LastAssetBuildFailed = true; 939 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
861 BSPhysObject xprim = prim; 940 PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
862 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", 941 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
863 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
864 Util.FireAndForget(delegate
865 {
866 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
867 if (assetProvider != null)
868 {
869 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
870 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
871 {
872 if (!yprim.BaseShape.SculptEntry)
873 return;
874 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
875 return;
876
877 yprim.BaseShape.SculptData = asset.Data;
878 // This will cause the prim to see that the filler shape is not the right
879 // one and try again to build the object.
880 // No race condition with the normal shape setting since the rebuild is at taint time.
881 yprim.ForceBodyShapeRebuild(false);
882
883 });
884 }
885 });
886 } 942 }
887 else 943 else
888 { 944 {
889 if (prim.LastAssetBuildFailed) 945 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
946 if (prim.BaseShape.SculptEntry
947 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
948 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
949 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
950 )
890 { 951 {
891 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", 952 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
892 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); 953 // Multiple requestors will know we're waiting for this asset
954 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
955
956 BSPhysObject xprim = prim;
957 Util.FireAndForget(delegate
958 {
959 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
960 if (assetProvider != null)
961 {
962 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
963 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
964 {
965 bool assetFound = false;
966 string mismatchIDs = String.Empty; // DEBUG DEBUG
967 if (asset != null && yprim.BaseShape.SculptEntry)
968 {
969 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
970 {
971 yprim.BaseShape.SculptData = asset.Data;
972 // This will cause the prim to see that the filler shape is not the right
973 // one and try again to build the object.
974 // No race condition with the normal shape setting since the rebuild is at taint time.
975 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
976 assetFound = true;
977 }
978 else
979 {
980 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
981 }
982 }
983 if (assetFound)
984 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
985 else
986 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
987 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
988 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
989
990 });
991 }
992 else
993 {
994 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
995 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
996 LogHeader, PhysicsScene.Name);
997 }
998 });
999 }
1000 else
1001 {
1002 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1003 {
1004 PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
1005 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
1006 }
893 } 1007 }
894 } 1008 }
895 1009
896 // While we figure out the real problem, stick a simple native shape on the object. 1010 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
897 BulletShape fillinShape = 1011 BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 1012 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
899 1013
900 return fillinShape; 1014 return fillinShape;
901 } 1015 }
@@ -904,49 +1018,45 @@ public sealed class BSShapeCollection : IDisposable
904 // Updates prim.BSBody with the information about the new body if one is created. 1018 // Updates prim.BSBody with the information about the new body if one is created.
905 // Returns 'true' if an object was actually created. 1019 // Returns 'true' if an object was actually created.
906 // Called at taint-time. 1020 // Called at taint-time.
907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 1021 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback)
908 BodyDestructionCallback bodyCallback)
909 { 1022 {
910 bool ret = false; 1023 bool ret = false;
911 1024
912 // the mesh, hull or native shape must have already been created in Bullet 1025 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 1026 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
914 1027
915 // If there is an existing body, verify it's of an acceptable type. 1028 // 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. 1029 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
917 if (!mustRebuild) 1030 if (!mustRebuild)
918 { 1031 {
919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); 1032 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 1033 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 1034 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
922 { 1035 {
923 // If the collisionObject is not the correct type for solidness, rebuild what's there 1036 // If the collisionObject is not the correct type for solidness, rebuild what's there
924 mustRebuild = true; 1037 mustRebuild = true;
1038 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
925 } 1039 }
926 } 1040 }
927 1041
928 if (mustRebuild || forceRebuild) 1042 if (mustRebuild || forceRebuild)
929 { 1043 {
930 // Free any old body 1044 // Free any old body
931 DereferenceBody(prim.PhysBody, true, bodyCallback); 1045 DereferenceBody(prim.PhysBody, bodyCallback);
932 1046
933 BulletBody aBody; 1047 BulletBody aBody;
934 IntPtr bodyPtr = IntPtr.Zero;
935 if (prim.IsSolid) 1048 if (prim.IsSolid)
936 { 1049 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 1050 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 1051 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 } 1052 }
941 else 1053 else
942 { 1054 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 1055 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 1056 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 } 1057 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 1058
949 ReferenceBody(aBody, true); 1059 ReferenceBody(aBody);
950 1060
951 prim.PhysBody = aBody; 1061 prim.PhysBody = aBody;
952 1062
@@ -956,13 +1066,13 @@ public sealed class BSShapeCollection : IDisposable
956 return ret; 1066 return ret;
957 } 1067 }
958 1068
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) 1069 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
960 { 1070 {
961 bool ret = false; 1071 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc(); 1072 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values) 1073 foreach (MeshDesc md in Meshes.Values)
964 { 1074 {
965 if (md.ptr == addr) 1075 if (md.shape.ReferenceSame(shape))
966 { 1076 {
967 foundDesc = md; 1077 foundDesc = md;
968 ret = true; 1078 ret = true;
@@ -974,13 +1084,13 @@ public sealed class BSShapeCollection : IDisposable
974 return ret; 1084 return ret;
975 } 1085 }
976 1086
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) 1087 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
978 { 1088 {
979 bool ret = false; 1089 bool ret = false;
980 HullDesc foundDesc = new HullDesc(); 1090 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values) 1091 foreach (HullDesc hd in Hulls.Values)
982 { 1092 {
983 if (hd.ptr == addr) 1093 if (hd.shape.ReferenceSame(shape))
984 { 1094 {
985 foundDesc = hd; 1095 foundDesc = hd;
986 ret = true; 1096 ret = true;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index 96cd55e..ee18379 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -27,24 +27,19 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Text; 30using System.Text;
32 31
32using OMV = OpenMetaverse;
33
33namespace OpenSim.Region.Physics.BulletSPlugin 34namespace OpenSim.Region.Physics.BulletSPlugin
34{ 35{
35public abstract class BSShape 36public abstract class BSShape
36{ 37{
37 public IntPtr ptr { get; set; }
38 public BSPhysicsShapeType type { get; set; }
39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; } 38 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; } 39 public DateTime lastReferenced { get; set; }
42 40
43 public BSShape() 41 public BSShape()
44 { 42 {
45 ptr = IntPtr.Zero;
46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0;
48 referenceCount = 0; 43 referenceCount = 0;
49 lastReferenced = DateTime.Now; 44 lastReferenced = DateTime.Now;
50 } 45 }
@@ -63,7 +58,7 @@ public abstract class BSShape
63 } 58 }
64 59
65 // Compound shapes are handled special as they are rebuilt from scratch. 60 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created. 61 // This isn't too great a hardship since most of the child shapes will have already been created.
67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) 62 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 { 63 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added 64 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
@@ -71,6 +66,14 @@ public abstract class BSShape
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); 66 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 } 67 }
73 68
69 // Avatars have their own unique shape
70 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
71 {
72 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
73 ret = BSShapeAvatar.GetReference(prim);
74 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
75 }
76
74 if (ret == null) 77 if (ret == null)
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); 78 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
76 79
@@ -91,15 +94,17 @@ public abstract class BSShape
91 // All shapes have a static call to get a reference to the physical shape 94 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference(); 95 // protected abstract static BSShape GetReference();
93 96
97 // Returns a string for debugging that uniquily identifies the memory used by this instance
98 public virtual string AddrString
99 {
100 get { return "unknown"; }
101 }
102
94 public override string ToString() 103 public override string ToString()
95 { 104 {
96 StringBuilder buff = new StringBuilder(); 105 StringBuilder buff = new StringBuilder();
97 buff.Append("<p="); 106 buff.Append("<p=");
98 buff.Append(ptr.ToString("X")); 107 buff.Append(AddrString);
99 buff.Append(",s=");
100 buff.Append(type.ToString());
101 buff.Append(",k=");
102 buff.Append(key.ToString("X"));
103 buff.Append(",c="); 108 buff.Append(",c=");
104 buff.Append(referenceCount.ToString()); 109 buff.Append(referenceCount.ToString());
105 buff.Append(">"); 110 buff.Append(">");
@@ -126,7 +131,8 @@ public class BSShapeNative : BSShape
126 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 131 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
127 { 132 {
128 // Native shapes are not shared and are always built anew. 133 // Native shapes are not shared and are always built anew.
129 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); 134 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
135 return null;
130 } 136 }
131 137
132 private BSShapeNative(BSScene physicsScene, BSPhysObject prim, 138 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
@@ -141,14 +147,15 @@ public class BSShapeNative : BSShape
141 nativeShapeData.HullKey = (ulong)shapeKey; 147 nativeShapeData.HullKey = (ulong)shapeKey;
142 148
143 149
150 /*
144 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 151 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
145 { 152 {
146 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); 153 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
147 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 154 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
148 } 155 }
149 else 156 else
150 { 157 {
151 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); 158 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
152 } 159 }
153 if (ptr == IntPtr.Zero) 160 if (ptr == IntPtr.Zero)
154 { 161 {
@@ -157,15 +164,18 @@ public class BSShapeNative : BSShape
157 } 164 }
158 type = shapeType; 165 type = shapeType;
159 key = (UInt64)shapeKey; 166 key = (UInt64)shapeKey;
167 */
160 } 168 }
161 // Make this reference to the physical shape go away since native shapes are not shared. 169 // Make this reference to the physical shape go away since native shapes are not shared.
162 public override void Dereference(BSScene physicsScene) 170 public override void Dereference(BSScene physicsScene)
163 { 171 {
172 /*
164 // Native shapes are not tracked and are released immediately 173 // Native shapes are not tracked and are released immediately
165 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); 174 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
166 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr); 175 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
167 ptr = IntPtr.Zero; 176 ptr = IntPtr.Zero;
168 // Garbage collection will free up this instance. 177 // Garbage collection will free up this instance.
178 */
169 } 179 }
170} 180}
171 181
@@ -205,4 +215,143 @@ public class BSShapeCompound : BSShape
205 } 215 }
206 public override void Dereference(BSScene physicsScene) { } 216 public override void Dereference(BSScene physicsScene) { }
207} 217}
218
219public class BSShapeAvatar : BSShape
220{
221 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
222 public BSShapeAvatar() : base()
223 {
224 }
225 public static BSShape GetReference(BSPhysObject prim)
226 {
227 return new BSShapeNull();
228 }
229 public override void Dereference(BSScene physicsScene) { }
230
231 // From the front:
232 // A---A
233 // / \
234 // B-------B
235 // / \ +Z
236 // C-----------C |
237 // \ / -Y --+-- +Y
238 // \ / |
239 // \ / -Z
240 // D-----D
241 // \ /
242 // E-E
243
244 // From the top A and E are just lines.
245 // B, C and D are hexagons:
246 //
247 // C1--C2 +X
248 // / \ |
249 // C0 C3 -Y --+-- +Y
250 // \ / |
251 // C5--C4 -X
252
253 // Zero goes directly through the middle so the offsets are from that middle axis
254 // and up and down from a middle horizon (A and E are the same distance from the zero).
255 // The height, width and depth is one. All scaling is done by the simulator.
256
257 // Z component -- how far the level is from the middle zero
258 private const float Aup = 0.5f;
259 private const float Bup = 0.4f;
260 private const float Cup = 0.3f;
261 private const float Dup = -0.4f;
262 private const float Eup = -0.5f;
263
264 // Y component -- distance from center to x0 and x3
265 private const float Awid = 0.25f;
266 private const float Bwid = 0.3f;
267 private const float Cwid = 0.5f;
268 private const float Dwid = 0.3f;
269 private const float Ewid = 0.2f;
270
271 // Y component -- distance from center to x1, x2, x4 and x5
272 private const float Afwid = 0.0f;
273 private const float Bfwid = 0.2f;
274 private const float Cfwid = 0.4f;
275 private const float Dfwid = 0.2f;
276 private const float Efwid = 0.0f;
277
278 // X component -- distance from zero to the front or back of a level
279 private const float Adep = 0f;
280 private const float Bdep = 0.3f;
281 private const float Cdep = 0.5f;
282 private const float Ddep = 0.2f;
283 private const float Edep = 0f;
284
285 private OMV.Vector3[] avatarVertices = {
286 new OMV.Vector3( 0.0f, -Awid, Aup), // A0
287 new OMV.Vector3( 0.0f, +Awid, Aup), // A3
288
289 new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
290 new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
291 new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
292 new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
293 new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
294 new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
295
296 new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
297 new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
298 new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
299 new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
300 new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
301 new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
302
303 new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
304 new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
305 new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
306 new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
307 new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
308 new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
309
310 new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
311 new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
312 };
313
314 // Offsets of the vertices in the vertices array
315 private enum Ind : int
316 {
317 A0, A3,
318 B0, B1, B2, B3, B4, B5,
319 C0, C1, C2, C3, C4, C5,
320 D0, D1, D2, D3, D4, D5,
321 E0, E3
322 }
323
324 // Comments specify trianges and quads in clockwise direction
325 private Ind[] avatarIndices = {
326 Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
327 Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
328 Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
329 Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
330 Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
331 Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
332
333 Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
334 Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
335 Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
336 Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
337 Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
338 Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
339
340 Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
341 Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
342 Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
343 Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
344 Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
345 Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
346
347 Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
348 Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
349 Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
350 Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
351 Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
352 Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
353
354 };
355
356}
208} 357}
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..b2fb835 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,41 +122,49 @@ 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 {
135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
130 // The ground plane is here to catch things that are trying to drop to negative infinity 136 // The ground plane is here to catch things that are trying to drop to negative infinity
131 BulletShape groundPlaneShape = new BulletShape( 137 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 138 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE); 139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 140
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 141 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
136 Vector3.Zero, Quaternion.Identity)); 142 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 143 // Ground plane does not move
140 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 144 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
141 // Everything collides with the ground plane. 145 // Everything collides with the ground plane.
142 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 146 m_groundPlane.collisionType = CollisionType.Groundplane;
143 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 147 m_groundPlane.ApplyCollisionMask(PhysicsScene);
144 148
145 // 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);
147 m_terrains.Add(Vector3.Zero, initialTerrain); 150 lock (m_terrains)
151 {
152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
153 m_terrains.Add(Vector3.Zero, initialTerrain);
154 }
148 } 155 }
149 156
150 // Release all the terrain structures we might have allocated 157 // Release all the terrain structures we might have allocated
151 public void ReleaseGroundPlaneAndTerrain() 158 public void ReleaseGroundPlaneAndTerrain()
152 { 159 {
153 if (m_groundPlane.ptr != IntPtr.Zero) 160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
161 if (m_groundPlane.HasPhysicalBody)
154 { 162 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) 163 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
156 { 164 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); 165 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane);
158 } 166 }
159 m_groundPlane.ptr = IntPtr.Zero; 167 m_groundPlane.Clear();
160 } 168 }
161 169
162 ReleaseTerrain(); 170 ReleaseTerrain();
@@ -165,17 +173,22 @@ public sealed class BSTerrainManager
165 // Release all the terrain we have allocated 173 // Release all the terrain we have allocated
166 public void ReleaseTerrain() 174 public void ReleaseTerrain()
167 { 175 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) 176 lock (m_terrains)
169 { 177 {
170 kvp.Value.Dispose(); 178 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
179 {
180 kvp.Value.Dispose();
181 }
182 m_terrains.Clear();
171 } 183 }
172 m_terrains.Clear();
173 } 184 }
174 185
175 // The simulator wants to set a new heightmap for the terrain. 186 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) { 187 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap; 188 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 189 // If there are multiple requests for changes to the same terrain between ticks,
190 // only do that last one.
191 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
179 { 192 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 193 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 { 194 {
@@ -185,11 +198,16 @@ public sealed class BSTerrainManager
185 // the terrain is added to our parent 198 // the terrain is added to our parent
186 if (MegaRegionParentPhysicsScene is BSScene) 199 if (MegaRegionParentPhysicsScene is BSScene)
187 { 200 {
188 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 201 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
189 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 202 // This looks really odd but this region is passing its terrain to its mega-region root region
190 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( 203 // and the creation of the terrain must happen on the root region's taint thread and not
191 BSScene.CHILDTERRAIN_ID, localHeightMap, 204 // my taint thread.
192 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 205 ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate()
206 {
207 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
208 BSScene.CHILDTERRAIN_ID, localHeightMap,
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
210 });
193 } 211 }
194 } 212 }
195 else 213 else
@@ -198,29 +216,30 @@ public sealed class BSTerrainManager
198 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 216 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
199 217
200 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, 218 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
201 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 219 m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
202 } 220 }
203 }); 221 });
204 } 222 }
205 223
206 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain 224 // If called for terrain has has not been previously allocated, a new terrain will be built
207 // based on the passed information. The 'id' should be either the terrain id or 225 // based on the passed information. The 'id' should be either the terrain id or
208 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 226 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
209 // The latter feature is for creating child terrains for mega-regions. 227 // The latter feature is for creating child terrains for mega-regions.
210 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 228 // If there is an existing terrain body, a new
211 // terrain shape is created and added to the body. 229 // 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. 230 // 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.) 231 // (The above does suggest that some simplification/refactoring is in order.)
232 // Called during taint-time.
214 private void UpdateTerrain(uint id, float[] heightMap, 233 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 234 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 { 235 {
217 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 236 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}",
218 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); 237 BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime);
219 238
220 // Find high and low points of passed heightmap. 239 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum 240 // 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 241 // 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. 242 // terrain so replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue; 243 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 244 float maxZ = float.MinValue;
226 foreach (float height in heightMap) 245 foreach (float height in heightMap)
@@ -238,15 +257,15 @@ public sealed class BSTerrainManager
238 257
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 258 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240 259
241 BSTerrainPhys terrainPhys; 260 lock (m_terrains)
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 { 261 {
244 // There is already a terrain in this spot. Free the old and build the new. 262 BSTerrainPhys terrainPhys;
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 263 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 { 264 {
265 // There is already a terrain in this spot. Free the old and build the new.
266 DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
267 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
268
250 // Remove old terrain from the collection 269 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase); 270 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using. 271 // Release any physical memory it may be using.
@@ -254,6 +273,7 @@ public sealed class BSTerrainManager
254 273
255 if (MegaRegionParentPhysicsScene == null) 274 if (MegaRegionParentPhysicsScene == null)
256 { 275 {
276 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
257 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 277 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
258 m_terrains.Add(terrainRegionBase, newTerrainPhys); 278 m_terrains.Add(terrainRegionBase, newTerrainPhys);
259 279
@@ -271,35 +291,24 @@ public sealed class BSTerrainManager
271 // I hate doing this, but just bail 291 // I hate doing this, but just bail
272 return; 292 return;
273 } 293 }
274 }); 294 }
275 } 295 else
276 else 296 {
277 { 297 // 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 298 // 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 299
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 300 // if this is a child terrain, calculate a unique terrain id
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 301 uint newTerrainID = id;
302 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
303 newTerrainID = ++m_terrainCount;
292 304
293 // Code that must happen at taint-time 305 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() 306 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); 307 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys); 308 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300 309
301 m_terrainModified = true; 310 m_terrainModified = true;
302 }); 311 }
303 } 312 }
304 } 313 }
305 314
@@ -308,9 +317,9 @@ public sealed class BSTerrainManager
308 { 317 {
309 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 318 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
310 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 319 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
311 (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); 320 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
312 BSTerrainPhys newTerrainPhys = null; 321 BSTerrainPhys newTerrainPhys = null;
313 switch ((int)PhysicsScene.Params.terrainImplementation) 322 switch ((int)BSParam.TerrainImplementation)
314 { 323 {
315 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 324 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
316 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 325 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
@@ -323,14 +332,68 @@ public sealed class BSTerrainManager
323 default: 332 default:
324 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 333 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
325 LogHeader, 334 LogHeader,
326 (int)PhysicsScene.Params.terrainImplementation, 335 (int)BSParam.TerrainImplementation,
327 PhysicsScene.Params.terrainImplementation, 336 BSParam.TerrainImplementation,
328 PhysicsScene.RegionName, terrainRegionBase); 337 PhysicsScene.RegionName, terrainRegionBase);
329 break; 338 break;
330 } 339 }
331 return newTerrainPhys; 340 return newTerrainPhys;
332 } 341 }
333 342
343 // Return 'true' of this position is somewhere in known physical terrain space
344 public bool IsWithinKnownTerrain(Vector3 pos)
345 {
346 Vector3 terrainBaseXYZ;
347 BSTerrainPhys physTerrain;
348 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
349 }
350
351 // Return a new position that is over known terrain if the position is outside our terrain.
352 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
353 {
354 Vector3 ret = pPos;
355
356 // First, base addresses are never negative so correct for that possible problem.
357 if (ret.X < 0f || ret.Y < 0f)
358 {
359 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
360 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
361 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
362 BSScene.DetailLogZero, pPos, ret);
363 }
364
365 // Can't do this function if we don't know about any terrain.
366 if (m_terrains.Count == 0)
367 return ret;
368
369 int loopPrevention = 10;
370 Vector3 terrainBaseXYZ;
371 BSTerrainPhys physTerrain;
372 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
373 {
374 // The passed position is not within a known terrain area.
375 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
376
377 // Must be off the top of a region. Find an adjacent region to move into.
378 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
379
380 ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X));
381 ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y));
382 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
383 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
384
385 if (loopPrevention-- < 0f)
386 {
387 // The 'while' is a little dangerous so this prevents looping forever if the
388 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
389 // the list of terrains is in transition.
390 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
391 break;
392 }
393 }
394
395 return ret;
396 }
334 397
335 // Given an X and Y, find the height of the terrain. 398 // Given an X and Y, find the height of the terrain.
336 // Since we could be handling multiple terrains for a mega-region, 399 // Since we could be handling multiple terrains for a mega-region,
@@ -341,40 +404,125 @@ public sealed class BSTerrainManager
341 private float lastHeightTX = 999999f; 404 private float lastHeightTX = 999999f;
342 private float lastHeightTY = 999999f; 405 private float lastHeightTY = 999999f;
343 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 406 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
344 public float GetTerrainHeightAtXYZ(Vector3 loc) 407 public float GetTerrainHeightAtXYZ(Vector3 pos)
345 { 408 {
346 float tX = loc.X; 409 float tX = pos.X;
347 float tY = loc.Y; 410 float tY = pos.Y;
348 // You'd be surprized at the number of times this routine is called 411 // You'd be surprized at the number of times this routine is called
349 // with the same parameters as last time. 412 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 413 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
351 return lastHeight; 414 return lastHeight;
415 m_terrainModified = false;
352 416
353 lastHeightTX = tX; 417 lastHeightTX = tX;
354 lastHeightTY = tY; 418 lastHeightTY = tY;
355 float ret = HEIGHT_GETHEIGHT_RET; 419 float ret = HEIGHT_GETHEIGHT_RET;
356 420
357 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 421 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; 422 BSTerrainPhys physTerrain;
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) 423 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
363 { 424 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 425 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
367 } 426 }
368 else 427 else
369 { 428 {
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 429 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
371 LogHeader, PhysicsScene.RegionName, tX, tY); 430 LogHeader, PhysicsScene.RegionName, tX, tY);
431 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
432 BSScene.DetailLogZero, pos, terrainBaseXYZ);
372 } 433 }
373 m_terrainModified = false; 434
374 lastHeight = ret; 435 lastHeight = ret;
375 return ret; 436 return ret;
376 } 437 }
377 438
439 public float GetWaterLevelAtXYZ(Vector3 pos)
440 {
441 float ret = WATER_HEIGHT_GETHEIGHT_RET;
442
443 Vector3 terrainBaseXYZ;
444 BSTerrainPhys physTerrain;
445 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
446 {
447 ret = physTerrain.GetWaterLevelAtXYZ(pos);
448 }
449 else
450 {
451 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
452 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
453 }
454 return ret;
455 }
456
457 // Given an address, return 'true' of there is a description of that terrain and output
458 // the descriptor class and the 'base' fo the addresses therein.
459 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
460 {
461 bool ret = false;
462
463 Vector3 terrainBaseXYZ = Vector3.Zero;
464 if (pos.X < 0f || pos.Y < 0f)
465 {
466 // We don't handle negative addresses so just make up a base that will not be found.
467 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
468 }
469 else
470 {
471 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
472 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
473 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
474 }
475
476 BSTerrainPhys physTerrain = null;
477 lock (m_terrains)
478 {
479 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
480 }
481 outTerrainBase = terrainBaseXYZ;
482 outPhysTerrain = physTerrain;
483 return ret;
484 }
485
486 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
487 // this one. Usually used to return an out of bounds object to a known place.
488 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
489 {
490 Vector3 ret = pTerrainBase;
491
492 // Can't do this function if we don't know about any terrain.
493 if (m_terrains.Count == 0)
494 return ret;
495
496 // Just some sanity
497 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
498 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
499 ret.Z = 0f;
500
501 lock (m_terrains)
502 {
503 // Once down to the <0,0> region, we have to be done.
504 while (ret.X > 0f || ret.Y > 0f)
505 {
506 if (ret.X > 0f)
507 {
508 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
509 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
510 if (m_terrains.ContainsKey(ret))
511 break;
512 }
513 if (ret.Y > 0f)
514 {
515 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
516 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
517 if (m_terrains.ContainsKey(ret))
518 break;
519 }
520 }
521 }
522
523 return ret;
524 }
525
378 // Although no one seems to check this, I do support combining. 526 // Although no one seems to check this, I do support combining.
379 public bool SupportsCombining() 527 public bool SupportsCombining()
380 { 528 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150..2ce1513 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -76,27 +76,43 @@ public sealed class BSTerrainMesh : BSTerrainPhys
76 m_sizeX = (int)(maxCoords.X - minCoords.X); 76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y); 77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78 78
79 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, 79 bool meshCreationSuccess = false;
80 m_sizeX, m_sizeY, 80 if (BSParam.TerrainMeshMagnification == 1)
81 (float)m_sizeX, (float)m_sizeY, 81 {
82 Vector3.Zero, 1.0f, 82 // If a magnification of one, use the old routine that is tried and true.
83 out indicesCount, out indices, out verticesCount, out vertices)) 83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene,
84 initialMap, m_sizeX, m_sizeY, // input size
85 Vector3.Zero, // base for mesh
86 out indicesCount, out indices, out verticesCount, out vertices);
87 }
88 else
89 {
90 // Other magnifications use the newer routine
91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene,
92 initialMap, m_sizeX, m_sizeY, // input size
93 BSParam.TerrainMeshMagnification,
94 physicsScene.TerrainManager.DefaultRegionSize,
95 Vector3.Zero, // base for mesh
96 out indicesCount, out indices, out verticesCount, out vertices);
97 }
98 if (!meshCreationSuccess)
84 { 99 {
85 // DISASTER!! 100 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); 101 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
87 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); 102 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
88 // Something is very messed up and a crash is in our future. 103 // Something is very messed up and a crash is in our future.
89 return; 104 return;
90 } 105 }
91 106
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 107 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
93 indicesCount, indices, verticesCount, vertices), 108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
94 BSPhysicsShapeType.SHAPE_MESH); 109
95 if (m_terrainShape.ptr == IntPtr.Zero) 110 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
111 if (!m_terrainShape.HasPhysicalShape)
96 { 112 {
97 // DISASTER!! 113 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); 114 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
99 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); 115 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
100 // Something is very messed up and a crash is in our future. 116 // Something is very messed up and a crash is in our future.
101 return; 117 return;
102 } 118 }
@@ -104,49 +120,58 @@ public sealed class BSTerrainMesh : BSTerrainPhys
104 Vector3 pos = regionBase; 120 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity; 121 Quaternion rot = Quaternion.Identity;
106 122
107 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); 123 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
108 if (m_terrainBody.ptr == IntPtr.Zero) 124 if (!m_terrainBody.HasPhysicalBody)
109 { 125 {
110 // DISASTER!! 126 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 127 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
112 // Something is very messed up and a crash is in our future. 128 // Something is very messed up and a crash is in our future.
113 return; 129 return;
114 } 130 }
131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
115 132
116 // Set current terrain attributes 133 // Set current terrain attributes
117 BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); 134 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
118 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); 135 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
119 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 136 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
120 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 137 PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
138 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
121 139
122 // Static objects are not very massive. 140 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 141 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
124 142
125 // Return the new terrain to the world of physical objects 143 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 144 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);
127 145
128 // redo its bounding box now that it is in the world 146 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 147 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);
130 148
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 149 m_terrainBody.collisionType = CollisionType.Terrain;
132 (uint)CollisionFilterGroups.TerrainFilter, 150 m_terrainBody.ApplyCollisionMask(PhysicsScene);
133 (uint)CollisionFilterGroups.TerrainMask); 151
152 if (BSParam.UseSingleSidedMeshes)
153 {
154 PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
155 PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
156 }
134 157
135 // Make it so the terrain will not move or be considered for movement. 158 // Make it so the terrain will not move or be considered for movement.
136 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 159 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
137 } 160 }
138 161
139 public override void Dispose() 162 public override void Dispose()
140 { 163 {
141 if (m_terrainBody.ptr != IntPtr.Zero) 164 if (m_terrainBody.HasPhysicalBody)
142 { 165 {
143 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 166 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody);
144 // Frees both the body and the shape. 167 // Frees both the body and the shape.
145 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); 168 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody);
169 m_terrainBody.Clear();
170 m_terrainShape.Clear();
146 } 171 }
147 } 172 }
148 173
149 public override float GetHeightAtXYZ(Vector3 pos) 174 public override float GetTerrainHeightAtXYZ(Vector3 pos)
150 { 175 {
151 // For the moment use the saved heightmap to get the terrain height. 176 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position. 177 // TODO: raycast downward to find the true terrain below the position.
@@ -167,14 +192,17 @@ public sealed class BSTerrainMesh : BSTerrainPhys
167 return ret; 192 return ret;
168 } 193 }
169 194
195 // The passed position is relative to the base of the region.
196 public override float GetWaterLevelAtXYZ(Vector3 pos)
197 {
198 return PhysicsScene.SimpleWaterLevel;
199 }
200
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created. 202 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh( 203 public static bool ConvertHeightmapToMesh( BSScene physicsScene,
173 BSScene physicsScene,
174 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap 204 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
175 float extentX, float extentY, // zero based range for output vertices
176 Vector3 extentBase, // base to be added to all vertices 205 Vector3 extentBase, // base to be added to all vertices
177 float magnification, // number of vertices to create between heightMap coords
178 out int indicesCountO, out int[] indicesO, 206 out int indicesCountO, out int[] indicesO,
179 out int verticesCountO, out float[] verticesO) 207 out int verticesCountO, out float[] verticesO)
180 { 208 {
@@ -188,43 +216,47 @@ public sealed class BSTerrainMesh : BSTerrainPhys
188 // Simple mesh creation which assumes magnification == 1. 216 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result. 217 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190 218
219 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
220 // from zero to <= sizeX). The triangle indices are then generated as two triangles
221 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
222 // column of vertices are used to complete the triangles of the last row and column
223 // of the heightmap.
191 try 224 try
192 { 225 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge. 226 // One vertice per heightmap value plus the vertices off the side and bottom edge.
194 int totalVertices = (sizeX + 1) * (sizeY + 1); 227 int totalVertices = (sizeX + 1) * (sizeY + 1);
195 vertices = new float[totalVertices * 3]; 228 vertices = new float[totalVertices * 3];
196 int totalIndices = sizeX * sizeY * 6; 229 int totalIndices = sizeX * sizeY * 6;
197 indices = new int[totalIndices]; 230 indices = new int[totalIndices];
198 231
199 float magX = (float)sizeX / extentX; 232 if (physicsScene != null)
200 float magY = (float)sizeY / extentY; 233 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 234 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 235 float minHeight = float.MaxValue;
203 // Note that sizeX+1 vertices are created since there is land between this and the next region. 236 // 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++) 237 for (int yy = 0; yy <= sizeY; yy++)
205 { 238 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times 239 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
207 { 240 {
208 int offset = yy * sizeX + xx; 241 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column 242 // Extend the height with the height from the last row or column
210 if (yy == sizeY) offset -= sizeX; 243 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1; 244 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset]; 245 float height = heightMap[offset];
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 246 minHeight = Math.Min(minHeight, height);
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 247 vertices[verticesCount + 0] = (float)xx + extentBase.X;
248 vertices[verticesCount + 1] = (float)yy + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z; 249 vertices[verticesCount + 2] = height + extentBase.Z;
216 verticesCount += 3; 250 verticesCount += 3;
217 } 251 }
218 } 252 }
219 verticesCount = verticesCount / 3; 253 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222 254
223 for (int yy = 0; yy < sizeY; yy++) 255 for (int yy = 0; yy < sizeY; yy++)
224 { 256 {
225 for (int xx = 0; xx < sizeX; xx++) 257 for (int xx = 0; xx < sizeX; xx++)
226 { 258 {
227 int offset = yy * sizeX + xx; 259 int offset = yy * (sizeX + 1) + xx;
228 // Each vertices is presumed to be the upper left corner of a box of two triangles 260 // Each vertices is presumed to be the upper left corner of a box of two triangles
229 indices[indicesCount + 0] = offset; 261 indices[indicesCount + 0] = offset;
230 indices[indicesCount + 1] = offset + 1; 262 indices[indicesCount + 1] = offset + 1;
@@ -235,13 +267,166 @@ public sealed class BSTerrainMesh : BSTerrainPhys
235 indicesCount += 6; 267 indicesCount += 6;
236 } 268 }
237 } 269 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG 270
239 LogHeader, indicesCount); // DEBUG 271 ret = true;
272 }
273 catch (Exception e)
274 {
275 if (physicsScene != null)
276 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
277 LogHeader, physicsScene.RegionName, extentBase, e);
278 }
279
280 indicesCountO = indicesCount;
281 indicesO = indices;
282 verticesCountO = verticesCount;
283 verticesO = vertices;
284
285 return ret;
286 }
287
288 private class HeightMapGetter
289 {
290 private float[] m_heightMap;
291 private int m_sizeX;
292 private int m_sizeY;
293 public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
294 {
295 m_heightMap = pHeightMap;
296 m_sizeX = pSizeX;
297 m_sizeY = pSizeY;
298 }
299 // The heightmap is extended as an infinite plane at the last height
300 public float GetHeight(int xx, int yy)
301 {
302 int offset = 0;
303 // Extend the height with the height from the last row or column
304 if (yy >= m_sizeY)
305 if (xx >= m_sizeX)
306 offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
307 else
308 offset = (m_sizeY - 1) * m_sizeX + xx;
309 else
310 if (xx >= m_sizeX)
311 offset = yy * m_sizeX + (m_sizeX - 1);
312 else
313 offset = yy * m_sizeX + xx;
314
315 return m_heightMap[offset];
316 }
317 }
318
319 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
320 // Version that handles magnification.
321 // Return 'true' if successfully created.
322 public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
323 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
324 int magnification, // number of vertices per heighmap step
325 Vector3 extent, // dimensions of the output mesh
326 Vector3 extentBase, // base to be added to all vertices
327 out int indicesCountO, out int[] indicesO,
328 out int verticesCountO, out float[] verticesO)
329 {
330 bool ret = false;
331
332 int indicesCount = 0;
333 int verticesCount = 0;
334 int[] indices = new int[0];
335 float[] vertices = new float[0];
336
337 HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
338
339 // The vertices dimension of the output mesh
340 int meshX = sizeX * magnification;
341 int meshY = sizeY * magnification;
342 // The output size of one mesh step
343 float meshXStep = extent.X / meshX;
344 float meshYStep = extent.Y / meshY;
345
346 // Create an array of vertices that is meshX+1 by meshY+1 (note the loop
347 // from zero to <= meshX). The triangle indices are then generated as two triangles
348 // per heightmap point. There are meshX by meshY of these squares. The extra row and
349 // column of vertices are used to complete the triangles of the last row and column
350 // of the heightmap.
351 try
352 {
353 // Vertices for the output heightmap plus one on the side and bottom to complete triangles
354 int totalVertices = (meshX + 1) * (meshY + 1);
355 vertices = new float[totalVertices * 3];
356 int totalIndices = meshX * meshY * 6;
357 indices = new int[totalIndices];
358
359 if (physicsScene != null)
360 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
361 BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
362 totalVertices, totalIndices, extentBase);
363
364 float minHeight = float.MaxValue;
365 // Note that sizeX+1 vertices are created since there is land between this and the next region.
366 // Loop through the output vertices and compute the mediun height in between the input vertices
367 for (int yy = 0; yy <= meshY; yy++)
368 {
369 for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
370 {
371 float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
372 int stepY = (int)offsetY;
373 float fractionalY = offsetY - (float)stepY;
374 float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
375 int stepX = (int)offsetX;
376 float fractionalX = offsetX - (float)stepX;
377
378 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
379 // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
380
381 // get the four corners of the heightmap square the mesh point is in
382 float heightUL = hmap.GetHeight(stepX , stepY );
383 float heightUR = hmap.GetHeight(stepX + 1, stepY );
384 float heightLL = hmap.GetHeight(stepX , stepY + 1);
385 float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
386
387 // bilinear interplolation
388 float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
389 + heightUR * fractionalX * (1 - fractionalY)
390 + heightLL * (1 - fractionalX) * fractionalY
391 + heightLR * fractionalX * fractionalY;
392
393 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
394 // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
395
396 minHeight = Math.Min(minHeight, height);
397
398 vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
399 vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
400 vertices[verticesCount + 2] = height + extentBase.Z;
401 verticesCount += 3;
402 }
403 }
404 // The number of vertices generated
405 verticesCount /= 3;
406
407 // Loop through all the heightmap squares and create indices for the two triangles for that square
408 for (int yy = 0; yy < meshY; yy++)
409 {
410 for (int xx = 0; xx < meshX; xx++)
411 {
412 int offset = yy * (meshX + 1) + xx;
413 // Each vertices is presumed to be the upper left corner of a box of two triangles
414 indices[indicesCount + 0] = offset;
415 indices[indicesCount + 1] = offset + 1;
416 indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
417 indices[indicesCount + 3] = offset + 1;
418 indices[indicesCount + 4] = offset + meshX + 2;
419 indices[indicesCount + 5] = offset + meshX + 1;
420 indicesCount += 6;
421 }
422 }
423
240 ret = true; 424 ret = true;
241 } 425 }
242 catch (Exception e) 426 catch (Exception e)
243 { 427 {
244 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", 428 if (physicsScene != null)
429 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
245 LogHeader, physicsScene.RegionName, extentBase, e); 430 LogHeader, physicsScene.RegionName, extentBase, e);
246 } 431 }
247 432
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..8012d91
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -0,0 +1,269 @@
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
118 // Make another reference to this physical object.
119 public virtual BulletShape Clone() { return new BulletShape(); }
120
121 // Return 'true' if this and other refer to the same physical object
122 public virtual bool ReferenceSame(BulletShape xx) { return false; }
123
124 // Used for log messages for a unique display of the memory/object allocated to this instance
125 public virtual string AddrString
126 {
127 get { return "unknown"; }
128 }
129
130 public override string ToString()
131 {
132 StringBuilder buff = new StringBuilder();
133 buff.Append("<p=");
134 buff.Append(AddrString);
135 buff.Append(",s=");
136 buff.Append(type.ToString());
137 buff.Append(",k=");
138 buff.Append(shapeKey.ToString("X"));
139 buff.Append(",n=");
140 buff.Append(isNativeShape.ToString());
141 buff.Append(">");
142 return buff.ToString();
143 }
144}
145
146// An allocated Bullet btConstraint
147public class BulletConstraint
148{
149 public BulletConstraint()
150 {
151 }
152 public virtual void Clear() { }
153 public virtual bool HasPhysicalConstraint { get { return false; } }
154
155 // Used for log messages for a unique display of the memory/object allocated to this instance
156 public virtual string AddrString
157 {
158 get { return "unknown"; }
159 }
160}
161
162// An allocated HeightMapThing which holds various heightmap info.
163// Made a class rather than a struct so there would be only one
164// instance of this and C# will pass around pointers rather
165// than making copies.
166public class BulletHMapInfo
167{
168 public BulletHMapInfo(uint id, float[] hm) {
169 ID = id;
170 heightMap = hm;
171 terrainRegionBase = OMV.Vector3.Zero;
172 minCoords = new OMV.Vector3(100f, 100f, 25f);
173 maxCoords = new OMV.Vector3(101f, 101f, 26f);
174 minZ = maxZ = 0f;
175 sizeX = sizeY = 256f;
176 }
177 public uint ID;
178 public float[] heightMap;
179 public OMV.Vector3 terrainRegionBase;
180 public OMV.Vector3 minCoords;
181 public OMV.Vector3 maxCoords;
182 public float sizeX, sizeY;
183 public float minZ, maxZ;
184 public BulletShape terrainShape;
185 public BulletBody terrainBody;
186}
187
188// The general class of collsion object.
189public enum CollisionType
190{
191 Avatar,
192 Groundplane,
193 Terrain,
194 Static,
195 Dynamic,
196 VolumeDetect,
197 // Linkset, // A linkset should be either Static or Dynamic
198 LinksetChild,
199 Unknown
200};
201
202// Hold specification of group and mask collision flags for a CollisionType
203public struct CollisionTypeFilterGroup
204{
205 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
206 {
207 type = t;
208 group = g;
209 mask = m;
210 }
211 public CollisionType type;
212 public uint group;
213 public uint mask;
214};
215
216public static class BulletSimData
217{
218
219// Map of collisionTypes to flags for collision groups and masks.
220// An object's 'group' is the collison groups this object belongs to
221// An object's 'filter' is the groups another object has to belong to in order to collide with me
222// A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0)
223//
224// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
225// but, instead, use references to this dictionary. Finding and debugging
226// collision flag problems will be made easier.
227public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
228 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
229{
230 { CollisionType.Avatar,
231 new CollisionTypeFilterGroup(CollisionType.Avatar,
232 (uint)CollisionFilterGroups.BCharacterGroup,
233 (uint)CollisionFilterGroups.BAllGroup)
234 },
235 { CollisionType.Groundplane,
236 new CollisionTypeFilterGroup(CollisionType.Groundplane,
237 (uint)CollisionFilterGroups.BGroundPlaneGroup,
238 (uint)CollisionFilterGroups.BAllGroup)
239 },
240 { CollisionType.Terrain,
241 new CollisionTypeFilterGroup(CollisionType.Terrain,
242 (uint)CollisionFilterGroups.BTerrainGroup,
243 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
244 },
245 { CollisionType.Static,
246 new CollisionTypeFilterGroup(CollisionType.Static,
247 (uint)CollisionFilterGroups.BStaticGroup,
248 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
249 },
250 { CollisionType.Dynamic,
251 new CollisionTypeFilterGroup(CollisionType.Dynamic,
252 (uint)CollisionFilterGroups.BSolidGroup,
253 (uint)(CollisionFilterGroups.BAllGroup))
254 },
255 { CollisionType.VolumeDetect,
256 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
257 (uint)CollisionFilterGroups.BSensorTrigger,
258 (uint)(~CollisionFilterGroups.BSensorTrigger))
259 },
260 { CollisionType.LinksetChild,
261 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
262 (uint)CollisionFilterGroups.BLinksetChildGroup,
263 (uint)(CollisionFilterGroups.BNoneGroup))
264 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
265 },
266};
267
268}
269}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
new file mode 100755
index 0000000..8a15abe
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -0,0 +1,346 @@
1CURRENT PRIORITIES
2=================================================
3Use the HACD convex hull routine in Bullet rather than the C# version.
4 Speed up hullifying large meshes.
5Enable vehicle border crossings (at least as poorly as ODE)
6 Terrain skirts
7 Avatar created in previous region and not new region when crossing border
8 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
9Lock axis
10Deleting a linkset while standing on the root will leave the physical shape of the root behind.
11 Not sure if it is because standing on it. Done with large prim linksets.
12Linkset child rotations.
13 Nebadon spiral tube has middle sections which are rotated wrong.
14 Select linked spiral tube. Delink and note where the middle section ends up.
15Vehicle angular vertical attraction
16vehicle angular banking
17Center-of-gravity
18Vehicle angular deflection
19 Preferred orientation angular correction fix
20when should angular and linear motor targets be zeroed? when selected?
21 Need a vehicle.clear()? Or an 'else' in prestep if not physical.
22Teravus llMoveToTarget script debug
23 Mixing of hover, buoyancy/gravity, moveToTarget, into one force
24 Setting hover height to zero disables hover even if hover flags are on (from SL wiki)
25limitMotorUp calibration (more down?)
26llRotLookAt
27llLookAt
28Avatars walking up stairs (HALF DONE)
29Avatar movement
30 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
31 walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
32 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
33Vehicle script tuning/debugging
34 Avanti speed script
35 Weapon shooter script
36Move material definitions (friction, ...) into simulator.
37Add material densities to the material types.
38Terrain detail: double terrain mesh detail
39One sided meshes? Should terrain be built into a closed shape?
40 When meshes get partially wedged into the terrain, they cannot push themselves out.
41 It is possible that Bullet processes collisions whether entering or leaving a mesh.
42 Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869
43
44VEHICLES TODO LIST:
45=================================================
46Border crossing with linked vehicle causes crash
47 20121129.1411: editting/moving phys object across region boundries causes crash
48 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
49Vehicles (Move smoothly)
50Some vehicles should not be able to turn if no speed or off ground.
51What to do if vehicle and prim buoyancy differ?
52Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
53Neb car jiggling left and right
54 Happens on terrain and any other mesh object. Flat cubes are much smoother.
55 This has been reduced but not eliminated.
56Implement referenceFrame for all the motion routines.
57For limitMotorUp, use raycast down to find if vehicle is in the air.
58Verify llGetVel() is returning a smooth and good value for vehicle movement.
59llGetVel() should return the root's velocity if requested in a child prim.
60Implement function efficiency for lineaar and angular motion.
61After getting off a vehicle, the root prim is phantom (can be walked through)
62 Need to force a position update for the root prim after compound shape destruction
63Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
64Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
65 A kludge that isn't fixing the real problem of Bullet adding extra motion.
66Incorporate inter-relationship of angular corrections. For instance, angularDeflection
67 and angularMotorUp will compute same X or Y correction. When added together
68 creates over-correction and over-shoot and wabbling.
69Vehicle attributes are not restored when a vehicle is rezzed on region creation
70 Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized.
71
72GENERAL TODO LIST:
73=================================================
74Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
75 Regular triangle meshes don't do physical collisions.
76Resitution of a prim works on another prim but not on terrain.
77 The dropped prim doesn't bounce properly on the terrain.
78Add a sanity check for PIDTarget location.
79Level-of-detail for mesh creation. Prims with circular interiors require lod of 32.
80 Is much saved with lower LODs? At the moment, all set to 32.
81Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't.
82 If arrow show at prim, collision reported about 1/3 of time. If collision reported,
83 both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times.
84 Shooting 5m sphere "arrows" at 60m/s.
85llMoveToTarget objects are not effected by gravity until target is removed.
86Compute CCD parameters based on body size
87Can solver iterations be changed per body/shape? Can be for constraints but what
88 about regular vehicles?
89Implement llSetPhysicalMaterial.
90 extend it with Center-of-mass, rolling friction, density
91Implement llSetForceAndTorque.
92Change BSPrim.moveToTarget to used forces rather than changing position
93 Changing position allows one to move through walls
94Implement an avatar mesh shape. The Bullet capsule is way too limited.
95 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
96Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
97Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
98Duplicating a physical prim causes old prim to jump away
99 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
100Scenes with hundred of thousands of static objects take a lot of physics CPU time.
101BSPrim.Force should set a continious force on the prim. The force should be
102 applied each tick. Some limits?
103Gun sending shooter flying.
104Collision margin (gap between physical objects lying on each other)
105Boundry checking (crashes related to crossing boundry)
106 Add check for border edge position for avatars and objects.
107 Verify the events are created for border crossings.
108Avatar rotation (check out changes to ScenePresence for physical rotation)
109Avatar running (what does phys engine need to do?)
110Small physical objects do not interact correctly
111 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
112 The chain will fall apart and pairs will dance around on ground
113 Chains of 1x1x.2 will stay connected but will dance.
114 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
115Add PID motor for avatar movement (slow to stop, ...)
116setForce should set a constant force. Different than AddImpulse.
117Implement raycast.
118Implement ShapeCollection.Dispose()
119Implement water as a plain so raycasting and collisions can happen with same.
120Add collision penetration return
121 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
122Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
123 Also osGetPhysicsEngineVerion() maybe.
124Linkset.Position and Linkset.Orientation requre rewrite to properly return
125 child position. LinksetConstraint acts like it's at taint time!!
126Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
127Should the different PID factors have non-equal contributions for different
128 values of Efficiency?
129Selecting and deselecting physical objects causes CPU processing time to jump
130 http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1
131 put thousand physical objects, select and deselect same. CPU time will be large.
132Re-implement buoyancy as a separate force on the object rather than diddling gravity.
133 Register a pre-step event to add the force.
134More efficient memory usage when passing hull information from BSPrim to BulletSim
135Avatar movement motor check for zero or small movement. Somehow suppress small movements
136 when avatar has stopped and is just standing. Simple test for near zero has
137 the problem of preventing starting up (increase from zero) especially when falling.
138Physical and phantom will drop through the terrain
139
140
141LINKSETS
142======================================================
143Child prims do not report collisions
144Allow children of a linkset to be phantom:
145 http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html
146 Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast.
147Editing a child of a linkset causes the child to go phantom
148 Move a child prim once when it is physical and can never move it again without it going phantom
149Offset the center of the linkset to be the geometric center of all the prims
150 Not quite the same as the center-of-gravity
151Linksets should allow collisions to individual children
152 Add LocalID to children shapes in LinksetCompound and create events for individuals
153LinksetCompound: when one of the children changes orientation (like tires
154 turning on a vehicle, the whole compound object is rebuilt. Optimize this
155 so orientation/position of individual children can change without a rebuild.
156Verify/think through scripts in children of linksets. What do they reference
157 and return when getting position, velocity, ...
158Confirm constraint linksets still work after making all the changes for compound linksets.
159Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding
160Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
161 For compound linksets, add ability to remove or reposition individual child shapes.
162Speed up creation of large physical linksets
163 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
164 REALLY bad for very large physical linksets (freezes the sim for many seconds).
165Eliminate collisions between objects in a linkset. (LinksetConstraint)
166 Have UserPointer point to struct with localID and linksetID?
167 Objects in original linkset still collide with each other?
168
169MORE
170======================================================
171Create tests for different interface components
172 Have test objects/scripts measure themselves and turn color if correct/bad
173 Test functions in SL and calibrate correctness there
174 Create auto rezzer and tracker to run through the tests
175Do we need to do convex hulls all the time? Can complex meshes be left meshes?
176 There is some problem with meshes and collisions
177 Hulls are not as detailed as meshes. Hulled vehicles insides are different shape.
178Debounce avatar contact so legs don't keep folding up when standing.
179Implement LSL physics controls. Like STATUS_ROTATE_X.
180Add border extensions to terrain to help region crossings and objects leaving region.
181Use a different capsule shape for avatar when sitting
182 LL uses a pyrimidal shape scaled by the avatar's bounding box
183 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
184Performance test with lots of avatars. Can BulletSim support a thousand?
185Optimize collisions in C++: only send up to the object subscribed to collisions.
186 Use collision subscription and remove the collsion(A,B) and collision(B,A)
187Check whether SimMotionState needs large if statement (see TODO).
188Implement 'top colliders' info.
189Avatar jump
190Performance measurement and changes to make quicker.
191Implement detailed physics stats (GetStats()).
192Measure performance improvement from hulls
193Test not using ghost objects for volume detect implementation.
194Performance of closures and delegates for taint processing
195 Are there faster ways?
196 Is any slowdown introduced by the existing implementation significant?
197Is there are more efficient method of implementing pre and post step actions?
198 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
199Physics Arena central pyramid: why is one side permiable?
200In SL, perfect spheres don't seem to have rolling friction. Add special case.
201Enforce physical parameter min/max:
202 Gravity: [-1, 28]
203 Friction: [0, 255]
204 Density: [1, 22587]
205 Restitution [0, 1]
206 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
207Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
208Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html
209
210INTERNAL IMPROVEMENT/CLEANUP
211=================================================
212Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
213 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
214Create the physical wrapper classes (BulletBody, BulletShape) by methods on
215 BSAPITemplate and make their actual implementation Bullet engine specific.
216 For the short term, just call the existing functions in ShapeCollection.
217Consider moving prim/character body and shape destruction in destroy()
218 to postTimeTime rather than protecting all the potential sets that
219 might have been queued up.
220Remove unused fields from ShapeData (not used in API2)
221Remove unused fields from pinned memory shared parameter block
222 Create parameter variables in BSScene to replace same.
223Breakout code for mesh/hull/compound/native into separate BSShape* classes
224 Standardize access to building and reference code.
225 The skeleton classes are in the sources but are not complete or linked in.
226Make BSBody and BSShape real classes to centralize creation/changin/destruction
227 Convert state and parameter calls from BulletSimAPI direct calls to
228 calls on BSBody and BSShape
229Generalize Dynamics and PID with standardized motors.
230Generalize Linkset and vehicles into PropertyManagers
231 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
232 Potentially add events for shape destruction, etc.
233Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
234 BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc.
235Implement linkset by setting position of children when root updated. (LinksetManual)
236 Linkset implementation using manual prim movement.
237LinkablePrim class? Would that simplify/centralize the linkset logic?
238BSScene.UpdateParameterSet() is broken. How to set params on objects?
239Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
240 bob at the water level. BSPrim.PositionSanityCheck()
241Should taints check for existance or activeness of target?
242 When destroying linksets/etc, taints can be generated for objects that are
243 actually gone when the taint happens. Crashes don't happen because the taint closure
244 keeps the object from being freed, but that is just an accident.
245 Possibly have an 'active' flag that is checked by the taint processor?
246Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
247Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
248There are TOO MANY interfaces from BulletSim core to Bullet itself
249 Think of something to eliminate one or more of the layers
250
251THREADING
252=================================================
253Do taint action immediately if not actually executing Bullet.
254 Add lock around Bullet execution and just do taint actions if simulation is not happening.
255
256DONE DONE DONE DONE
257=================================================
258Cleanup code in BSDynamics by using motors. (Resolution: started)
259Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
260 Would have better and adjustable resolution.
261Build terrain mesh so heighmap is height of the center of the square meter.
262 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
263Terrain as mesh. (Resolution: done)
264How are static linksets seen by the physics engine?
265 Resolution: they are not linked in physics. When moved, all the children are repositioned.
266Convert BSCharacter to use all API2 (Resolution: done)
267Avatar pushing difficult (too heavy?)
268Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
269Remove old code in DLL (all non-API2 stuff). (Resolution: done)
270Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
271Debug Bullet internal stats output (why is timing all wrong?)
272 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
273Implement meshes or just verify that they work. (Resolution: they do!)
274Do prim hash codes work for sculpties and meshes? (Resolution: yes)
275Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
276 Compound shapes will need the LocalID in the shapes and collision
277 processing to get it from there.
278Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
279Package Bullet source mods for Bullet internal stats output
280 (Resolution: move code into WorldData.h rather than relying on patches)
281Single prim vehicles don't seem to properly vehiclize.
282 (Resolution: mass was not getting set properly for single prim linksets)
283Add material type linkage and input all the material property definitions.
284 Skeleton classes and table are in the sources but are not filled or used.
285 (Resolution:
286Neb vehicle taking > 25ms of physics time!!
287 (Resolution: compound linksets were being rebuild WAY too often)
288Avatar height off after unsitting (floats off ground)
289 Editting appearance then moving restores.
290 Must not be initializing height when recreating capsule after unsit.
291 (Resolution: confusion of scale vs size for native objects removed)
292Light cycle falling over when driving (Resolution: implemented angularMotorUp)
293Should vehicle angular/linear movement friction happen after all the components
294 or does it only apply to the basic movement?
295 (Resolution: friction added before returning newly computed motor value.
296 What is expected by some vehicles (turning up friction to moderate speed))
297Tune terrain/object friction to be closer to SL.
298 (Resolution: added material type with friction and resolution)
299Smooth avatar movement with motor (DONE)
300 Should motor update be all at taint-time? (Yes, DONE)
301 Fix avatar slowly sliding when standing (zero motion when stopped) (DONE)
302 (Resolution: added BSVMotor for avatar starting and stopping)
303llApplyImpulse()
304 Compare mass/movement in OS and SL. Calibrate actions. (DONE)
305 (Resolution: tested on SL and OS. AddForce scales the force for timestep)
306llSetBuoyancy() (DONE)
307 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
308Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
309 (Resolution: set default density to 3.5 (from 60) which is closer to SL)
310Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
311 (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
312Meshes rendering as bounding boxes (DONE)
313 (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
314llMoveToTarget (Resolution: added simple motor to update the position.)
315Angular motor direction is global coordinates rather than local coordinates (DONE)
316Add vehicle collisions so IsColliding is properly reported. (DONE)
317 Needed for banking, limitMotorUp, movementLimiting, ...
318 (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it)
319VehicleAddForce is not scaled by the simulation step but it is only
320 applied for one step. Should it be scaled? (DONE)
321 (Resolution: use force for timed things, Impulse for immediate, non-timed things)
322Complete implemention of preStepActions (DONE)
323 Replace vehicle step call with prestep event.
324 Is there a need for postStepActions? postStepTaints?
325Disable activity of passive linkset children. (DONE)
326 Since the linkset is a compound object, the old prims are left lying
327 around and need to be phantomized so they don't collide, ...
328Remove HeightmapInfo from terrain specification (DONE)
329 Since C++ code does not need terrain height, this structure et al are not needed.
330Surfboard go wonky when turning (DONE)
331 Angular motor direction is global coordinates rather than local coordinates?
332 (Resolution: made angular motor direction correct coordinate system)
333Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE)
334 Msg Kayaker on OSGrid when working
335 (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the
336 same in SL as in OS/BulletSim)
337Boats float low in the water (DONE)
338Boats floating at proper level (DONE)
339When is force introduced by SetForce removed? The prestep action could go forever. (DONE)
340 (Resolution: setForce registers a prestep action which keeps applying the force)
341Child movement in linkset (don't rebuild linkset) (DONE 20130122))
342Avatar standing on a moving object should start to move with the object. (DONE 20130125)
343Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
344 Verify that angular motion specified around Z moves in the vehicle coordinates.
345 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
346Nebadon vehicles turning funny in arena (DONE)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
index 0d1db3b..02b03a8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
new file mode 100755
index 0000000..33232bd
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
@@ -0,0 +1,150 @@
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 copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.Physics.BulletSPlugin;
38using OpenSim.Region.Physics.Manager;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin.Tests
44{
45[TestFixture]
46public class BasicVehicles : OpenSimTestCase
47{
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene PhysicsScene { get; set; }
52 BSPrim TestVehicle { get; set; }
53 Vector3 TestVehicleInitPosition { get; set; }
54 float simulationTimeStep = 0.089f;
55
56 [TestFixtureSetUp]
57 public void Init()
58 {
59 Dictionary<string, string> engineParams = new Dictionary<string, string>();
60 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
61
62 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
63 Vector3 pos = new Vector3(100.0f, 100.0f, 0f);
64 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f;
65 TestVehicleInitPosition = pos;
66 Vector3 size = new Vector3(1f, 1f, 1f);
67 pbs.Scale = size;
68 Quaternion rot = Quaternion.Identity;
69 bool isPhys = false;
70 uint localID = 123;
71
72 PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID);
73 TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID];
74 // The actual prim shape creation happens at taint time
75 PhysicsScene.ProcessTaints();
76
77 }
78
79 [TestFixtureTearDown]
80 public void TearDown()
81 {
82 if (PhysicsScene != null)
83 {
84 // The Dispose() will also free any physical objects in the scene
85 PhysicsScene.Dispose();
86 PhysicsScene = null;
87 }
88 }
89
90 [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)]
91 [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)]
92 [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)]
93 [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)]
94 // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */]
95 // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */]
96 // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */]
97 // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */]
98 // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */]
99 // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */]
100 // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */]
101 // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */]
102 public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw)
103 {
104 // Enough simulation steps to cover the timescale the operation should take
105 int simSteps = (int)(timeScale / simulationTimeStep) + 1;
106
107 // Tip the vehicle
108 Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw);
109 TestVehicle.Orientation = initOrientation;
110
111 TestVehicle.Position = TestVehicleInitPosition;
112
113 // The vehicle controller is not enabled directly (by setting a vehicle type).
114 // Instead the appropriate values are set and calls are made just the parts of the
115 // controller we want to exercise. Stepping the physics engine then applies
116 // the actions of that one feature.
117 TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
118 TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale);
119 TestVehicle.VehicleController.enableAngularVerticalAttraction = true;
120
121 TestVehicle.IsPhysical = true;
122 PhysicsScene.ProcessTaints();
123
124 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up
125 for (int ii = 0; ii < simSteps; ii++)
126 {
127 TestVehicle.VehicleController.ForgetKnownVehicleProperties();
128 TestVehicle.VehicleController.ComputeAngularVerticalAttraction();
129 TestVehicle.VehicleController.PushKnownChanged();
130
131 PhysicsScene.Simulate(simulationTimeStep);
132 }
133
134 TestVehicle.IsPhysical = false;
135 PhysicsScene.ProcessTaints();
136
137 // After these steps, the vehicle should be upright
138 /*
139 float finalRoll, finalPitch, finalYaw;
140 TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw);
141 Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f));
142 Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f));
143 Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f));
144 */
145
146 Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation;
147 Assert.That(upPointer.Z, Is.GreaterThan(0.99f));
148 }
149}
150} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs
new file mode 100755
index 0000000..35cbc1d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs
@@ -0,0 +1,56 @@
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 copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Tests.Common;
37
38namespace OpenSim.Region.Physics.BulletSPlugin.Tests
39{
40[TestFixture]
41public class BulletSimTests : OpenSimTestCase
42{
43 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
44 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
45
46 [TestFixtureSetUp]
47 public void Init()
48 {
49 }
50
51 [TestFixtureTearDown]
52 public void TearDown()
53 {
54 }
55}
56}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs
new file mode 100755
index 0000000..28207a4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs
@@ -0,0 +1,95 @@
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 copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Collections.Generic;
31using System.Linq;
32using System.Text;
33
34using Nini.Config;
35
36using OpenSim.Framework;
37using OpenSim.Region.Physics.BulletSPlugin;
38using OpenSim.Region.Physics.Meshing;
39
40namespace OpenSim.Region.Physics.BulletSPlugin.Tests
41{
42// Utility functions for building up and tearing down the sample physics environments
43public static class BulletSimTestsUtil
44{
45 // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA"
46 // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults)
47 // May be 'null' if there are no overrides.
48 public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides)
49 {
50 IConfigSource openSimINI = new IniConfigSource();
51 IConfig startupConfig = openSimINI.AddConfig("Startup");
52 startupConfig.Set("physics", "BulletSim");
53 startupConfig.Set("meshing", "Meshmerizer");
54 startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps
55
56 IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim");
57 // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged".
58 // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged");
59 // bulletSimConfig.Set("BulletEngine", "BulletXNA");
60 bulletSimConfig.Set("MeshSculptedPrim", "false");
61 bulletSimConfig.Set("ForceSimplePrimMeshing", "true");
62 if (paramOverrides != null)
63 {
64 foreach (KeyValuePair<string, string> kvp in paramOverrides)
65 {
66 bulletSimConfig.Set(kvp.Key, kvp.Value);
67 }
68 }
69
70 // If a special directory exists, put detailed logging therein.
71 // This allows local testing/debugging without having to worry that the build engine will output logs.
72 if (Directory.Exists("physlogs"))
73 {
74 bulletSimConfig.Set("PhysicsLoggingDir","./physlogs");
75 bulletSimConfig.Set("PhysicsLoggingEnabled","True");
76 bulletSimConfig.Set("PhysicsLoggingDoFlush","True");
77 bulletSimConfig.Set("VehicleLoggingEnabled","True");
78 }
79
80 BSPlugin bsPlugin = new BSPlugin();
81
82 BSScene bsScene = (BSScene)bsPlugin.GetScene("BSTestRegion");
83
84 // Since the asset requestor is not initialized, any mesh or sculptie will be a cube.
85 // In the future, add a fake asset fetcher to get meshes and sculpts.
86 // bsScene.RequestAssetMethod = ???;
87
88 Meshing.Meshmerizer mesher = new Meshmerizer(openSimINI);
89 bsScene.Initialise(mesher, openSimINI);
90
91 return bsScene;
92 }
93
94}
95}