aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics')
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs2
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs1885
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs1959
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs688
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs526
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs27
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs48
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs12
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1173
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs59
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs409
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs87
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs200
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs590
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs657
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs212
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs897
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs953
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs283
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs183
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs55
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs181
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs71
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs1015
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs265
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt324
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs4
-rw-r--r--OpenSim/Region/Physics/Manager/IMesher.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsActor.cs13
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs11
-rw-r--r--OpenSim/Region/Physics/Manager/ZeroMesher.cs9
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs26
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs5
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdePlugin.cs2
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs3
-rw-r--r--OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs3
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSPlugin.cs2
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSScene.cs4
-rw-r--r--OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs6
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs6
44 files changed, 9578 insertions, 3297 deletions
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs
index 7ab2a03..373c7e0 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
49 49
50 public PhysicsScene GetScene(string sceneIdentifier) 50 public PhysicsScene GetScene(string sceneIdentifier)
51 { 51 {
52 return new BasicScene(sceneIdentifier); 52 return new BasicScene(GetName(), sceneIdentifier);
53 } 53 }
54 54
55 public string GetName() 55 public string GetName()
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
index f5826ed..c4b9117 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
@@ -49,8 +49,10 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
49 49
50 //protected internal string sceneIdentifier; 50 //protected internal string sceneIdentifier;
51 51
52 public BasicScene(string _sceneIdentifier) 52 public BasicScene(string engineType, string _sceneIdentifier)
53 { 53 {
54 EngineType = engineType;
55 Name = EngineType + "/" + _sceneIdentifier;
54 //sceneIdentifier = _sceneIdentifier; 56 //sceneIdentifier = _sceneIdentifier;
55 } 57 }
56 58
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
new file mode 100755
index 0000000..ae54499
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -0,0 +1,1885 @@
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.SetShapeCollisionMargin2(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 CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
442 Vector3 pivotinA, Vector3 pivotinB,
443 Vector3 axisInA, Vector3 axisInB,
444 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
445{
446 BulletWorldUnman worldu = world as BulletWorldUnman;
447 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
448 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
449 return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
450 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
451}
452
453public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
454{
455 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
456 BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
457}
458
459public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
460{
461 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
462 BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
463}
464
465public override bool SetFrames(BulletConstraint constrain,
466 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
467{
468 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
469 return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
470}
471
472public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
473{
474 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
475 return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
476}
477
478public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
479{
480 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
481 return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
482}
483
484public override bool UseFrameOffset(BulletConstraint constrain, float enable)
485{
486 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
487 return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
488}
489
490public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
491{
492 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
493 return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
494}
495
496public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
497{
498 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
499 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
500}
501
502public override bool CalculateTransforms(BulletConstraint constrain)
503{
504 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
505 return BSAPICPP.CalculateTransforms2(constrainu.ptr);
506}
507
508public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
509{
510 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
511 return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
512}
513
514public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
515{
516 BulletWorldUnman worldu = world as BulletWorldUnman;
517 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
518 return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
519}
520
521// =====================================================================================
522// btCollisionWorld entries
523public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
524{
525 BulletWorldUnman worldu = world as BulletWorldUnman;
526 BulletBodyUnman bodyu = obj as BulletBodyUnman;
527 BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
528}
529
530public override void UpdateAabbs(BulletWorld world)
531{
532 BulletWorldUnman worldu = world as BulletWorldUnman;
533 BSAPICPP.UpdateAabbs2(worldu.ptr);
534}
535
536public override bool GetForceUpdateAllAabbs(BulletWorld world)
537{
538 BulletWorldUnman worldu = world as BulletWorldUnman;
539 return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
540}
541
542public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
543{
544 BulletWorldUnman worldu = world as BulletWorldUnman;
545 BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
546}
547
548// =====================================================================================
549// btDynamicsWorld entries
550public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
551{
552 BulletWorldUnman worldu = world as BulletWorldUnman;
553 BulletBodyUnman bodyu = obj as BulletBodyUnman;
554
555 // Bullet resets several variables when an object is added to the world.
556 // Gravity is reset to world default depending on the static/dynamic
557 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
558 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
559
560 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
561
562 if (ret)
563 {
564 BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
565 obj.ApplyCollisionMask(world.physicsScene);
566 }
567 return ret;
568}
569
570public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
571{
572 BulletWorldUnman worldu = world as BulletWorldUnman;
573 BulletBodyUnman bodyu = obj as BulletBodyUnman;
574 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
575}
576
577public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
578{
579 BulletWorldUnman worldu = world as BulletWorldUnman;
580 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
581 return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
582}
583
584public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
585{
586 BulletWorldUnman worldu = world as BulletWorldUnman;
587 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
588 return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
589}
590// =====================================================================================
591// btCollisionObject entries
592public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
593{
594 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
595 return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
596}
597
598public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
599{
600 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
601 return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
602}
603
604public override bool HasAnisotripicFriction(BulletConstraint constrain)
605{
606 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
607 return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
608}
609
610public override void SetContactProcessingThreshold(BulletBody obj, float val)
611{
612 BulletBodyUnman bodyu = obj as BulletBodyUnman;
613 BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
614}
615
616public override float GetContactProcessingThreshold(BulletBody obj)
617{
618 BulletBodyUnman bodyu = obj as BulletBodyUnman;
619 return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
620}
621
622public override bool IsStaticObject(BulletBody obj)
623{
624 BulletBodyUnman bodyu = obj as BulletBodyUnman;
625 return BSAPICPP.IsStaticObject2(bodyu.ptr);
626}
627
628public override bool IsKinematicObject(BulletBody obj)
629{
630 BulletBodyUnman bodyu = obj as BulletBodyUnman;
631 return BSAPICPP.IsKinematicObject2(bodyu.ptr);
632}
633
634public override bool IsStaticOrKinematicObject(BulletBody obj)
635{
636 BulletBodyUnman bodyu = obj as BulletBodyUnman;
637 return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
638}
639
640public override bool HasContactResponse(BulletBody obj)
641{
642 BulletBodyUnman bodyu = obj as BulletBodyUnman;
643 return BSAPICPP.HasContactResponse2(bodyu.ptr);
644}
645
646public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
647{
648 BulletWorldUnman worldu = world as BulletWorldUnman;
649 BulletBodyUnman bodyu = obj as BulletBodyUnman;
650 BulletShapeUnman shapeu = shape as BulletShapeUnman;
651 if (worldu != null && bodyu != null)
652 {
653 // Special case to allow the caller to zero out the reference to any physical shape
654 if (shapeu != null)
655 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
656 else
657 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
658 }
659}
660
661public override BulletShape GetCollisionShape(BulletBody obj)
662{
663 BulletBodyUnman bodyu = obj as BulletBodyUnman;
664 return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
665}
666
667public override int GetActivationState(BulletBody obj)
668{
669 BulletBodyUnman bodyu = obj as BulletBodyUnman;
670 return BSAPICPP.GetActivationState2(bodyu.ptr);
671}
672
673public override void SetActivationState(BulletBody obj, int state)
674{
675 BulletBodyUnman bodyu = obj as BulletBodyUnman;
676 BSAPICPP.SetActivationState2(bodyu.ptr, state);
677}
678
679public override void SetDeactivationTime(BulletBody obj, float dtime)
680{
681 BulletBodyUnman bodyu = obj as BulletBodyUnman;
682 BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
683}
684
685public override float GetDeactivationTime(BulletBody obj)
686{
687 BulletBodyUnman bodyu = obj as BulletBodyUnman;
688 return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
689}
690
691public override void ForceActivationState(BulletBody obj, ActivationState state)
692{
693 BulletBodyUnman bodyu = obj as BulletBodyUnman;
694 BSAPICPP.ForceActivationState2(bodyu.ptr, state);
695}
696
697public override void Activate(BulletBody obj, bool forceActivation)
698{
699 BulletBodyUnman bodyu = obj as BulletBodyUnman;
700 BSAPICPP.Activate2(bodyu.ptr, forceActivation);
701}
702
703public override bool IsActive(BulletBody obj)
704{
705 BulletBodyUnman bodyu = obj as BulletBodyUnman;
706 return BSAPICPP.IsActive2(bodyu.ptr);
707}
708
709public override void SetRestitution(BulletBody obj, float val)
710{
711 BulletBodyUnman bodyu = obj as BulletBodyUnman;
712 BSAPICPP.SetRestitution2(bodyu.ptr, val);
713}
714
715public override float GetRestitution(BulletBody obj)
716{
717 BulletBodyUnman bodyu = obj as BulletBodyUnman;
718 return BSAPICPP.GetRestitution2(bodyu.ptr);
719}
720
721public override void SetFriction(BulletBody obj, float val)
722{
723 BulletBodyUnman bodyu = obj as BulletBodyUnman;
724 BSAPICPP.SetFriction2(bodyu.ptr, val);
725}
726
727public override float GetFriction(BulletBody obj)
728{
729 BulletBodyUnman bodyu = obj as BulletBodyUnman;
730 return BSAPICPP.GetFriction2(bodyu.ptr);
731}
732
733public override Vector3 GetPosition(BulletBody obj)
734{
735 BulletBodyUnman bodyu = obj as BulletBodyUnman;
736 return BSAPICPP.GetPosition2(bodyu.ptr);
737}
738
739public override Quaternion GetOrientation(BulletBody obj)
740{
741 BulletBodyUnman bodyu = obj as BulletBodyUnman;
742 return BSAPICPP.GetOrientation2(bodyu.ptr);
743}
744
745public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
746{
747 BulletBodyUnman bodyu = obj as BulletBodyUnman;
748 BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
749}
750
751 /*
752public override IntPtr GetBroadphaseHandle(BulletBody obj)
753{
754 BulletBodyUnman bodyu = obj as BulletBodyUnman;
755 return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
756}
757
758public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
759{
760 BulletBodyUnman bodyu = obj as BulletBodyUnman;
761 BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
762}
763 */
764
765public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
766{
767 BulletBodyUnman bodyu = obj as BulletBodyUnman;
768 BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
769}
770
771public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
772{
773 BulletBodyUnman bodyu = obj as BulletBodyUnman;
774 BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
775}
776
777public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
778{
779 BulletBodyUnman bodyu = obj as BulletBodyUnman;
780 BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
781}
782
783public override float GetHitFraction(BulletBody obj)
784{
785 BulletBodyUnman bodyu = obj as BulletBodyUnman;
786 return BSAPICPP.GetHitFraction2(bodyu.ptr);
787}
788
789public override void SetHitFraction(BulletBody obj, float val)
790{
791 BulletBodyUnman bodyu = obj as BulletBodyUnman;
792 BSAPICPP.SetHitFraction2(bodyu.ptr, val);
793}
794
795public override CollisionFlags GetCollisionFlags(BulletBody obj)
796{
797 BulletBodyUnman bodyu = obj as BulletBodyUnman;
798 return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
799}
800
801public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
802{
803 BulletBodyUnman bodyu = obj as BulletBodyUnman;
804 return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
805}
806
807public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
808{
809 BulletBodyUnman bodyu = obj as BulletBodyUnman;
810 return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
811}
812
813public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
814{
815 BulletBodyUnman bodyu = obj as BulletBodyUnman;
816 return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
817}
818
819public override float GetCcdMotionThreshold(BulletBody obj)
820{
821 BulletBodyUnman bodyu = obj as BulletBodyUnman;
822 return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
823}
824
825
826public override void SetCcdMotionThreshold(BulletBody obj, float val)
827{
828 BulletBodyUnman bodyu = obj as BulletBodyUnman;
829 BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
830}
831
832public override float GetCcdSweptSphereRadius(BulletBody obj)
833{
834 BulletBodyUnman bodyu = obj as BulletBodyUnman;
835 return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
836}
837
838public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
839{
840 BulletBodyUnman bodyu = obj as BulletBodyUnman;
841 BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
842}
843
844public override IntPtr GetUserPointer(BulletBody obj)
845{
846 BulletBodyUnman bodyu = obj as BulletBodyUnman;
847 return BSAPICPP.GetUserPointer2(bodyu.ptr);
848}
849
850public override void SetUserPointer(BulletBody obj, IntPtr val)
851{
852 BulletBodyUnman bodyu = obj as BulletBodyUnman;
853 BSAPICPP.SetUserPointer2(bodyu.ptr, val);
854}
855
856// =====================================================================================
857// btRigidBody entries
858public override void ApplyGravity(BulletBody obj)
859{
860 BulletBodyUnman bodyu = obj as BulletBodyUnman;
861 BSAPICPP.ApplyGravity2(bodyu.ptr);
862}
863
864public override void SetGravity(BulletBody obj, Vector3 val)
865{
866 BulletBodyUnman bodyu = obj as BulletBodyUnman;
867 BSAPICPP.SetGravity2(bodyu.ptr, val);
868}
869
870public override Vector3 GetGravity(BulletBody obj)
871{
872 BulletBodyUnman bodyu = obj as BulletBodyUnman;
873 return BSAPICPP.GetGravity2(bodyu.ptr);
874}
875
876public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
877{
878 BulletBodyUnman bodyu = obj as BulletBodyUnman;
879 BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
880}
881
882public override void SetLinearDamping(BulletBody obj, float lin_damping)
883{
884 BulletBodyUnman bodyu = obj as BulletBodyUnman;
885 BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
886}
887
888public override void SetAngularDamping(BulletBody obj, float ang_damping)
889{
890 BulletBodyUnman bodyu = obj as BulletBodyUnman;
891 BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
892}
893
894public override float GetLinearDamping(BulletBody obj)
895{
896 BulletBodyUnman bodyu = obj as BulletBodyUnman;
897 return BSAPICPP.GetLinearDamping2(bodyu.ptr);
898}
899
900public override float GetAngularDamping(BulletBody obj)
901{
902 BulletBodyUnman bodyu = obj as BulletBodyUnman;
903 return BSAPICPP.GetAngularDamping2(bodyu.ptr);
904}
905
906public override float GetLinearSleepingThreshold(BulletBody obj)
907{
908 BulletBodyUnman bodyu = obj as BulletBodyUnman;
909 return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
910}
911
912public override void ApplyDamping(BulletBody obj, float timeStep)
913{
914 BulletBodyUnman bodyu = obj as BulletBodyUnman;
915 BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
916}
917
918public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
919{
920 BulletBodyUnman bodyu = obj as BulletBodyUnman;
921 BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
922}
923
924public override Vector3 GetLinearFactor(BulletBody obj)
925{
926 BulletBodyUnman bodyu = obj as BulletBodyUnman;
927 return BSAPICPP.GetLinearFactor2(bodyu.ptr);
928}
929
930public override void SetLinearFactor(BulletBody obj, Vector3 factor)
931{
932 BulletBodyUnman bodyu = obj as BulletBodyUnman;
933 BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
934}
935
936public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
937{
938 BulletBodyUnman bodyu = obj as BulletBodyUnman;
939 BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
940}
941
942// Add a force to the object as if its mass is one.
943// Deep down in Bullet: m_totalForce += force*m_linearFactor;
944public override void ApplyCentralForce(BulletBody obj, Vector3 force)
945{
946 BulletBodyUnman bodyu = obj as BulletBodyUnman;
947 BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
948}
949
950// Set the force being applied to the object as if its mass is one.
951public override void SetObjectForce(BulletBody obj, Vector3 force)
952{
953 BulletBodyUnman bodyu = obj as BulletBodyUnman;
954 BSAPICPP.SetObjectForce2(bodyu.ptr, force);
955}
956
957public override Vector3 GetTotalForce(BulletBody obj)
958{
959 BulletBodyUnman bodyu = obj as BulletBodyUnman;
960 return BSAPICPP.GetTotalForce2(bodyu.ptr);
961}
962
963public override Vector3 GetTotalTorque(BulletBody obj)
964{
965 BulletBodyUnman bodyu = obj as BulletBodyUnman;
966 return BSAPICPP.GetTotalTorque2(bodyu.ptr);
967}
968
969public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
970{
971 BulletBodyUnman bodyu = obj as BulletBodyUnman;
972 return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
973}
974
975public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
976{
977 BulletBodyUnman bodyu = obj as BulletBodyUnman;
978 BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
979}
980
981public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
982{
983 BulletBodyUnman bodyu = obj as BulletBodyUnman;
984 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
985}
986
987// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
988public override void ApplyTorque(BulletBody obj, Vector3 torque)
989{
990 BulletBodyUnman bodyu = obj as BulletBodyUnman;
991 BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
992}
993
994// Apply force at the given point. Will add torque to the object.
995// Deep down in Bullet: applyCentralForce(force);
996// applyTorque(rel_pos.cross(force*m_linearFactor));
997public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
998{
999 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1000 BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
1001}
1002
1003// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1004// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
1005public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
1006{
1007 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1008 BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
1009}
1010
1011// Apply impulse to the object's torque. Force is scaled by object's mass.
1012// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
1013public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
1014{
1015 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1016 BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
1017}
1018
1019// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1020// Deep down in Bullet: applyCentralImpulse(impulse);
1021// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
1022public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
1023{
1024 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1025 BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
1026}
1027
1028public override void ClearForces(BulletBody obj)
1029{
1030 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1031 BSAPICPP.ClearForces2(bodyu.ptr);
1032}
1033
1034public override void ClearAllForces(BulletBody obj)
1035{
1036 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1037 BSAPICPP.ClearAllForces2(bodyu.ptr);
1038}
1039
1040public override void UpdateInertiaTensor(BulletBody obj)
1041{
1042 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1043 BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
1044}
1045
1046public override Vector3 GetLinearVelocity(BulletBody obj)
1047{
1048 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1049 return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
1050}
1051
1052public override Vector3 GetAngularVelocity(BulletBody obj)
1053{
1054 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1055 return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
1056}
1057
1058public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
1059{
1060 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1061 BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
1062}
1063
1064public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
1065{
1066 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1067 BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
1068}
1069
1070public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
1071{
1072 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1073 return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
1074}
1075
1076public override void Translate(BulletBody obj, Vector3 trans)
1077{
1078 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1079 BSAPICPP.Translate2(bodyu.ptr, trans);
1080}
1081
1082public override void UpdateDeactivation(BulletBody obj, float timeStep)
1083{
1084 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1085 BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
1086}
1087
1088public override bool WantsSleeping(BulletBody obj)
1089{
1090 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1091 return BSAPICPP.WantsSleeping2(bodyu.ptr);
1092}
1093
1094public override void SetAngularFactor(BulletBody obj, float factor)
1095{
1096 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1097 BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
1098}
1099
1100public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
1101{
1102 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1103 BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
1104}
1105
1106public override Vector3 GetAngularFactor(BulletBody obj)
1107{
1108 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1109 return BSAPICPP.GetAngularFactor2(bodyu.ptr);
1110}
1111
1112public override bool IsInWorld(BulletWorld world, BulletBody obj)
1113{
1114 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1115 return BSAPICPP.IsInWorld2(bodyu.ptr);
1116}
1117
1118public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
1119{
1120 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1121 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1122 BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
1123}
1124
1125public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
1126{
1127 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1128 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1129 BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
1130}
1131
1132public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
1133{
1134 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1135 return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
1136}
1137
1138public override int GetNumConstraintRefs(BulletBody obj)
1139{
1140 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1141 return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
1142}
1143
1144public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
1145{
1146 BulletBodyUnman bodyu = body as BulletBodyUnman;
1147 return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
1148}
1149
1150// =====================================================================================
1151// btCollisionShape entries
1152
1153public override float GetAngularMotionDisc(BulletShape shape)
1154{
1155 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1156 return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
1157}
1158
1159public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
1160{
1161 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1162 return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
1163}
1164
1165public override bool IsPolyhedral(BulletShape shape)
1166{
1167 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1168 return BSAPICPP.IsPolyhedral2(shapeu.ptr);
1169}
1170
1171public override bool IsConvex2d(BulletShape shape)
1172{
1173 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1174 return BSAPICPP.IsConvex2d2(shapeu.ptr);
1175}
1176
1177public override bool IsConvex(BulletShape shape)
1178{
1179 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1180 return BSAPICPP.IsConvex2(shapeu.ptr);
1181}
1182
1183public override bool IsNonMoving(BulletShape shape)
1184{
1185 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1186 return BSAPICPP.IsNonMoving2(shapeu.ptr);
1187}
1188
1189public override bool IsConcave(BulletShape shape)
1190{
1191 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1192 return BSAPICPP.IsConcave2(shapeu.ptr);
1193}
1194
1195public override bool IsCompound(BulletShape shape)
1196{
1197 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1198 return BSAPICPP.IsCompound2(shapeu.ptr);
1199}
1200
1201public override bool IsSoftBody(BulletShape shape)
1202{
1203 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1204 return BSAPICPP.IsSoftBody2(shapeu.ptr);
1205}
1206
1207public override bool IsInfinite(BulletShape shape)
1208{
1209 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1210 return BSAPICPP.IsInfinite2(shapeu.ptr);
1211}
1212
1213public override void SetLocalScaling(BulletShape shape, Vector3 scale)
1214{
1215 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1216 BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
1217}
1218
1219public override Vector3 GetLocalScaling(BulletShape shape)
1220{
1221 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1222 return BSAPICPP.GetLocalScaling2(shapeu.ptr);
1223}
1224
1225public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
1226{
1227 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1228 return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
1229}
1230
1231public override int GetShapeType(BulletShape shape)
1232{
1233 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1234 return BSAPICPP.GetShapeType2(shapeu.ptr);
1235}
1236
1237public override void SetMargin(BulletShape shape, float val)
1238{
1239 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1240 BSAPICPP.SetMargin2(shapeu.ptr, val);
1241}
1242
1243public override float GetMargin(BulletShape shape)
1244{
1245 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1246 return BSAPICPP.GetMargin2(shapeu.ptr);
1247}
1248
1249// =====================================================================================
1250// Debugging
1251public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1252{
1253 BulletWorldUnman worldu = world as BulletWorldUnman;
1254 BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
1255 BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
1256}
1257
1258public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
1259{
1260 BulletWorldUnman worldu = world as BulletWorldUnman;
1261 BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
1262 BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
1263}
1264
1265public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
1266{
1267 BulletWorldUnman worldu = world as BulletWorldUnman;
1268 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1269 BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
1270}
1271
1272public override void DumpActivationInfo(BulletWorld world)
1273{
1274 BulletWorldUnman worldu = world as BulletWorldUnman;
1275 BSAPICPP.DumpActivationInfo2(worldu.ptr);
1276}
1277
1278public override void DumpAllInfo(BulletWorld world)
1279{
1280 BulletWorldUnman worldu = world as BulletWorldUnman;
1281 BSAPICPP.DumpAllInfo2(worldu.ptr);
1282}
1283
1284public override void DumpPhysicsStatistics(BulletWorld world)
1285{
1286 BulletWorldUnman worldu = world as BulletWorldUnman;
1287 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1288}
1289public override void ResetBroadphasePool(BulletWorld world)
1290{
1291 BulletWorldUnman worldu = world as BulletWorldUnman;
1292 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1293}
1294public override void ResetConstraintSolver(BulletWorld world)
1295{
1296 BulletWorldUnman worldu = world as BulletWorldUnman;
1297 BSAPICPP.ResetConstraintSolver(worldu.ptr);
1298}
1299
1300// =====================================================================================
1301// =====================================================================================
1302// =====================================================================================
1303// =====================================================================================
1304// =====================================================================================
1305// The actual interface to the unmanaged code
1306static class BSAPICPP
1307{
1308// ===============================================================================
1309// Link back to the managed code for outputting log messages
1310[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1311public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
1312
1313// ===============================================================================
1314// Initialization and simulation
1315[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1316public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
1317 int maxCollisions, IntPtr collisionArray,
1318 int maxUpdates, IntPtr updateArray,
1319 DebugLogCallback logRoutine);
1320
1321[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1322public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
1323 out int updatedEntityCount, out int collidersCount);
1324
1325[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1326public static extern void Shutdown2(IntPtr sim);
1327
1328[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1329public static extern bool PushUpdate2(IntPtr obj);
1330
1331[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1332public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
1333
1334// =====================================================================================
1335// Mesh, hull, shape and body creation helper routines
1336[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1337public static extern IntPtr CreateMeshShape2(IntPtr world,
1338 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1339 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1340
1341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1342public static extern IntPtr CreateHullShape2(IntPtr world,
1343 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1344
1345[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1346public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1347
1348[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1349public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1350
1351[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1352public static extern bool IsNativeShape2(IntPtr shape);
1353
1354[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1355public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin);
1356
1357[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1358public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
1359
1360[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1361public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
1362
1363[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1364public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
1365
1366[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1367public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
1368
1369[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1370public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1371
1372[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1373public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1374
1375[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1376public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1377
1378[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1379public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
1380
1381[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1382public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1383
1384[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1385public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
1386
1387[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1388public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
1389
1390[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1391public static extern int GetBodyType2(IntPtr obj);
1392
1393[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1394public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1395
1396[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1397public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1398
1399[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1400public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1401
1402[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1403public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1404
1405// =====================================================================================
1406// Terrain creation and helper routines
1407[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1408public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1409
1410[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1411public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1412 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1413 float scaleFactor, float collisionMargin);
1414
1415// =====================================================================================
1416// Constraint creation and helper routines
1417[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1418public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1419 Vector3 frame1loc, Quaternion frame1rot,
1420 Vector3 frame2loc, Quaternion frame2rot,
1421 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1422
1423[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1424public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1425 Vector3 joinPoint,
1426 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1427
1428[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1429public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1430 Vector3 pivotinA, Vector3 pivotinB,
1431 Vector3 axisInA, Vector3 axisInB,
1432 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1433
1434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1435public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1436
1437[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1438public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
1439
1440[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1441public static extern bool SetFrames2(IntPtr constrain,
1442 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
1443
1444[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1445public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1446
1447[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1448public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1449
1450[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1451public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
1452
1453[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1454public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
1455
1456[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1457public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1458
1459[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1460public static extern bool CalculateTransforms2(IntPtr constrain);
1461
1462[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1463public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
1464
1465[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1466public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
1467
1468// =====================================================================================
1469// btCollisionWorld entries
1470[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1471public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
1472
1473[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1474public static extern void UpdateAabbs2(IntPtr world);
1475
1476[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1477public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
1478
1479[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1480public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
1481
1482// =====================================================================================
1483// btDynamicsWorld entries
1484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1485public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1486
1487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1488public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1489
1490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1491public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1492
1493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1494public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
1495// =====================================================================================
1496// btCollisionObject entries
1497[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1498public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
1499
1500[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1501public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
1502
1503[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1504public static extern bool HasAnisotripicFriction2(IntPtr constrain);
1505
1506[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1507public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
1508
1509[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1510public static extern float GetContactProcessingThreshold2(IntPtr obj);
1511
1512[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1513public static extern bool IsStaticObject2(IntPtr obj);
1514
1515[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1516public static extern bool IsKinematicObject2(IntPtr obj);
1517
1518[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1519public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
1520
1521[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1522public static extern bool HasContactResponse2(IntPtr obj);
1523
1524[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1525public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
1526
1527[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1528public static extern IntPtr GetCollisionShape2(IntPtr obj);
1529
1530[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1531public static extern int GetActivationState2(IntPtr obj);
1532
1533[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1534public static extern void SetActivationState2(IntPtr obj, int state);
1535
1536[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1537public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
1538
1539[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1540public static extern float GetDeactivationTime2(IntPtr obj);
1541
1542[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1543public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
1544
1545[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1546public static extern void Activate2(IntPtr obj, bool forceActivation);
1547
1548[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1549public static extern bool IsActive2(IntPtr obj);
1550
1551[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1552public static extern void SetRestitution2(IntPtr obj, float val);
1553
1554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1555public static extern float GetRestitution2(IntPtr obj);
1556
1557[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1558public static extern void SetFriction2(IntPtr obj, float val);
1559
1560[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1561public static extern float GetFriction2(IntPtr obj);
1562
1563 /* Haven't defined the type 'Transform'
1564[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1565public static extern Transform GetWorldTransform2(IntPtr obj);
1566
1567[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1568public static extern void setWorldTransform2(IntPtr obj, Transform trans);
1569 */
1570
1571[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1572public static extern Vector3 GetPosition2(IntPtr obj);
1573
1574[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1575public static extern Quaternion GetOrientation2(IntPtr obj);
1576
1577[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1578public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
1579
1580[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1581public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
1582
1583[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1584public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
1585
1586 /*
1587[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1588public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
1589
1590[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1591public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
1592 */
1593
1594[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1595public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
1596
1597[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1598public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
1599
1600[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1601public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
1602
1603[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1604public static extern float GetHitFraction2(IntPtr obj);
1605
1606[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1607public static extern void SetHitFraction2(IntPtr obj, float val);
1608
1609[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1610public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1611
1612[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1613public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1614
1615[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1616public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1617
1618[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1619public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1620
1621[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1622public static extern float GetCcdMotionThreshold2(IntPtr obj);
1623
1624[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1625public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
1626
1627[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1628public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
1629
1630[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1631public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
1632
1633[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1634public static extern IntPtr GetUserPointer2(IntPtr obj);
1635
1636[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1637public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
1638
1639// =====================================================================================
1640// btRigidBody entries
1641[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1642public static extern void ApplyGravity2(IntPtr obj);
1643
1644[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1645public static extern void SetGravity2(IntPtr obj, Vector3 val);
1646
1647[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1648public static extern Vector3 GetGravity2(IntPtr obj);
1649
1650[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1651public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
1652
1653[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1654public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
1655
1656[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1657public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
1658
1659[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1660public static extern float GetLinearDamping2(IntPtr obj);
1661
1662[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1663public static extern float GetAngularDamping2(IntPtr obj);
1664
1665[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1666public static extern float GetLinearSleepingThreshold2(IntPtr obj);
1667
1668[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1669public static extern float GetAngularSleepingThreshold2(IntPtr obj);
1670
1671[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1672public static extern void ApplyDamping2(IntPtr obj, float timeStep);
1673
1674[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1675public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
1676
1677[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1678public static extern Vector3 GetLinearFactor2(IntPtr obj);
1679
1680[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1681public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
1682
1683 /*
1684[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1685public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
1686 */
1687
1688[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1689public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
1690
1691// Add a force to the object as if its mass is one.
1692[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1693public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
1694
1695// Set the force being applied to the object as if its mass is one.
1696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1697public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
1698
1699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1700public static extern Vector3 GetTotalForce2(IntPtr obj);
1701
1702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1703public static extern Vector3 GetTotalTorque2(IntPtr obj);
1704
1705[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1706public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
1707
1708[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1709public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
1710
1711[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1712public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
1713
1714[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1715public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
1716
1717// Apply force at the given point. Will add torque to the object.
1718[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1719public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
1720
1721// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1723public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
1724
1725// Apply impulse to the object's torque. Force is scaled by object's mass.
1726[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1727public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
1728
1729// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1730[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1731public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
1732
1733[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1734public static extern void ClearForces2(IntPtr obj);
1735
1736[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1737public static extern void ClearAllForces2(IntPtr obj);
1738
1739[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1740public static extern void UpdateInertiaTensor2(IntPtr obj);
1741
1742[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1743public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
1744
1745 /*
1746[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1747public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
1748 */
1749
1750[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1751public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1752
1753[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1754public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1755
1756[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1757public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1758
1759[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1760public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1761
1762[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1763public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1764
1765[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1766public static extern void Translate2(IntPtr obj, Vector3 trans);
1767
1768[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1769public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1770
1771[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1772public static extern bool WantsSleeping2(IntPtr obj);
1773
1774[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1775public static extern void SetAngularFactor2(IntPtr obj, float factor);
1776
1777[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1778public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1779
1780[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1781public static extern Vector3 GetAngularFactor2(IntPtr obj);
1782
1783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1784public static extern bool IsInWorld2(IntPtr obj);
1785
1786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1787public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1788
1789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1790public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1791
1792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1793public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1794
1795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1796public static extern int GetNumConstraintRefs2(IntPtr obj);
1797
1798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1799public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
1800
1801// =====================================================================================
1802// btCollisionShape entries
1803
1804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1805public static extern float GetAngularMotionDisc2(IntPtr shape);
1806
1807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1808public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1809
1810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1811public static extern bool IsPolyhedral2(IntPtr shape);
1812
1813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1814public static extern bool IsConvex2d2(IntPtr shape);
1815
1816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1817public static extern bool IsConvex2(IntPtr shape);
1818
1819[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1820public static extern bool IsNonMoving2(IntPtr shape);
1821
1822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1823public static extern bool IsConcave2(IntPtr shape);
1824
1825[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1826public static extern bool IsCompound2(IntPtr shape);
1827
1828[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1829public static extern bool IsSoftBody2(IntPtr shape);
1830
1831[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1832public static extern bool IsInfinite2(IntPtr shape);
1833
1834[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1835public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
1836
1837[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1838public static extern Vector3 GetLocalScaling2(IntPtr shape);
1839
1840[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1841public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
1842
1843[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1844public static extern int GetShapeType2(IntPtr shape);
1845
1846[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1847public static extern void SetMargin2(IntPtr shape, float val);
1848
1849[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1850public static extern float GetMargin2(IntPtr shape);
1851
1852// =====================================================================================
1853// Debugging
1854[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1855public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1856
1857[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1858public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1859
1860[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1861public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1862
1863[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1864public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1865
1866[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1867public static extern void DumpActivationInfo2(IntPtr sim);
1868
1869[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1870public static extern void DumpAllInfo2(IntPtr sim);
1871
1872[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1873public static extern void DumpPhysicsStatistics2(IntPtr sim);
1874
1875[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1876public static extern void ResetBroadphasePool(IntPtr sim);
1877
1878[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1879public static extern void ResetConstraintSolver(IntPtr sim);
1880
1881}
1882
1883}
1884
1885}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
new file mode 100755
index 0000000..49b1730
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -0,0 +1,1959 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.IO;
30using System.Text;
31
32using OpenSim.Framework;
33
34using OpenMetaverse;
35
36using BulletXNA;
37using BulletXNA.LinearMath;
38using BulletXNA.BulletCollision;
39using BulletXNA.BulletDynamics;
40using BulletXNA.BulletCollision.CollisionDispatch;
41
42namespace OpenSim.Region.Physics.BulletSPlugin
43{
44public sealed class BSAPIXNA : BSAPITemplate
45{
46private sealed class BulletWorldXNA : BulletWorld
47{
48 public DiscreteDynamicsWorld world;
49 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
50 : base(id, physScene)
51 {
52 world = xx;
53 }
54}
55
56private sealed class BulletBodyXNA : BulletBody
57{
58 public CollisionObject body;
59 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
60
61 public BulletBodyXNA(uint id, CollisionObject xx)
62 : base(id)
63 {
64 body = xx;
65 }
66 public override bool HasPhysicalBody
67 {
68 get { return body != null; }
69 }
70 public override void Clear()
71 {
72 body = null;
73 }
74 public override string AddrString
75 {
76 get { return "XNARigidBody"; }
77 }
78}
79
80private sealed class BulletShapeXNA : BulletShape
81{
82 public CollisionShape shape;
83 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
84 : base()
85 {
86 shape = xx;
87 type = typ;
88 }
89 public override bool HasPhysicalShape
90 {
91 get { return shape != null; }
92 }
93 public override void Clear()
94 {
95 shape = null;
96 }
97 public override BulletShape Clone()
98 {
99 return new BulletShapeXNA(shape, type);
100 }
101 public override bool ReferenceSame(BulletShape other)
102 {
103 BulletShapeXNA otheru = other as BulletShapeXNA;
104 return (otheru != null) && (this.shape == otheru.shape);
105
106 }
107 public override string AddrString
108 {
109 get { return "XNACollisionShape"; }
110 }
111}
112private sealed class BulletConstraintXNA : BulletConstraint
113{
114 public TypedConstraint constrain;
115 public BulletConstraintXNA(TypedConstraint xx) : base()
116 {
117 constrain = xx;
118 }
119
120 public override void Clear()
121 {
122 constrain = null;
123 }
124 public override bool HasPhysicalConstraint { get { return constrain != null; } }
125
126 // Used for log messages for a unique display of the memory/object allocated to this instance
127 public override string AddrString
128 {
129 get { return "XNAConstraint"; }
130 }
131}
132 internal int m_maxCollisions;
133 internal CollisionDesc[] m_collisionArray;
134
135 internal int m_maxUpdatesPerFrame;
136 internal EntityProperties[] m_updateArray;
137
138 private static int m_collisionsThisFrame;
139 private BSScene PhysicsScene { get; set; }
140
141 public override string BulletEngineName { get { return "BulletXNA"; } }
142 public override string BulletEngineVersion { get; protected set; }
143
144 public BSAPIXNA(string paramName, BSScene physScene)
145 {
146 PhysicsScene = physScene;
147 }
148
149 /// <summary>
150 ///
151 /// </summary>
152 /// <param name="p"></param>
153 /// <param name="p_2"></param>
154 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
155 {
156 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
157 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
158 world.RemoveRigidBody(body);
159 return true;
160 }
161
162 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
163 {
164 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
165 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
166 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
167
168 return true;
169
170 }
171
172 public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint)
173 {
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
176 world.RemoveConstraint(constraint);
177 return true;
178 }
179
180 public override void SetRestitution(BulletBody pCollisionObject, float pRestitution)
181 {
182 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
183 collisionObject.SetRestitution(pRestitution);
184 }
185
186 public override int GetShapeType(BulletShape pShape)
187 {
188 CollisionShape shape = (pShape as BulletShapeXNA).shape;
189 return (int)shape.GetShapeType();
190 }
191 public override void SetMargin(BulletShape pShape, float pMargin)
192 {
193 CollisionShape shape = (pShape as BulletShapeXNA).shape;
194 shape.SetMargin(pMargin);
195 }
196
197 public override float GetMargin(BulletShape pShape)
198 {
199 CollisionShape shape = (pShape as BulletShapeXNA).shape;
200 return shape.GetMargin();
201 }
202
203 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
204 {
205 CollisionShape shape = (pShape as BulletShapeXNA).shape;
206 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
207 shape.SetLocalScaling(ref vec);
208
209 }
210
211 public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold)
212 {
213 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
214 collisionObject.SetContactProcessingThreshold(contactprocessingthreshold);
215 }
216
217 public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold)
218 {
219 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
220 collisionObject.SetCcdMotionThreshold(pccdMotionThreashold);
221 }
222
223 public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius)
224 {
225 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
226 collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
227 }
228
229 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
230 {
231 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
232 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
233 }
234
235 public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
236 {
237 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
238 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
239 existingcollisionFlags |= pcollisionFlags;
240 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
241 return (CollisionFlags) (uint) existingcollisionFlags;
242 }
243
244 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
245 {
246 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
247 CollisionObject cbody = (pBody as BulletBodyXNA).body;
248 RigidBody rbody = cbody as RigidBody;
249
250 // Bullet resets several variables when an object is added to the world. In particular,
251 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
252 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
253 IndexedMatrix origPos = cbody.GetWorldTransform();
254 if (rbody != null)
255 {
256 IndexedVector3 origGrav = rbody.GetGravity();
257 world.AddRigidBody(rbody);
258 rbody.SetGravity(origGrav);
259 }
260 else
261 {
262 world.AddCollisionObject(rbody);
263 }
264 cbody.SetWorldTransform(origPos);
265
266 pBody.ApplyCollisionMask(pWorld.physicsScene);
267
268 //if (body.GetBroadphaseHandle() != null)
269 // world.UpdateSingleAabb(body);
270 return true;
271 }
272
273 public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState)
274 {
275 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
276 collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
277 }
278
279 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject)
280 {
281 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
282 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
283 world.UpdateSingleAabb(collisionObject);
284 }
285
286 public override void UpdateAabbs(BulletWorld pWorld) {
287 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
288 world.UpdateAabbs();
289 }
290 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
291 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
292 return world.GetForceUpdateAllAabbs();
293
294 }
295 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
296 {
297 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
298 world.SetForceUpdateAllAabbs(pForce);
299 }
300
301 public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask)
302 {
303 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
304 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
305 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
306 if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0)
307 return false;
308 return true;
309 }
310
311 public override void ClearAllForces(BulletBody pCollisionObject)
312 {
313 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
314 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
315 collisionObject.SetInterpolationLinearVelocity(ref zeroVector);
316 collisionObject.SetInterpolationAngularVelocity(ref zeroVector);
317 IndexedMatrix bodytransform = collisionObject.GetWorldTransform();
318
319 collisionObject.SetInterpolationWorldTransform(ref bodytransform);
320
321 if (collisionObject is RigidBody)
322 {
323 RigidBody rigidbody = collisionObject as RigidBody;
324 rigidbody.SetLinearVelocity(zeroVector);
325 rigidbody.SetAngularVelocity(zeroVector);
326 rigidbody.ClearForces();
327 }
328 }
329
330 public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3)
331 {
332 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
333 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
334 collisionObject.SetInterpolationAngularVelocity(ref vec);
335 }
336
337 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
338 {
339 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
340 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
341 body.SetAngularVelocity(ref vec);
342 }
343 public override Vector3 GetTotalForce(BulletBody pBody)
344 {
345 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
346 IndexedVector3 iv3 = body.GetTotalForce();
347 return new Vector3(iv3.X, iv3.Y, iv3.Z);
348 }
349 public override Vector3 GetTotalTorque(BulletBody pBody)
350 {
351 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
352 IndexedVector3 iv3 = body.GetTotalTorque();
353 return new Vector3(iv3.X, iv3.Y, iv3.Z);
354 }
355 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
356 {
357 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
358 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
359 return new Vector3(iv3.X, iv3.Y, iv3.Z);
360 }
361 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
362 {
363 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
364 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
365 body.SetInvInertiaDiagLocal(ref iv3);
366 }
367 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
368 {
369 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
370 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
371 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
372 body.ApplyForce(ref forceiv3, ref posiv3);
373 }
374 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
375 {
376 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
377 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
378 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
379 body.ApplyImpulse(ref impiv3, ref posiv3);
380 }
381
382 public override void ClearForces(BulletBody pBody)
383 {
384 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
385 body.ClearForces();
386 }
387
388 public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation)
389 {
390 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
391 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
392 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
393 _orientation.W);
394 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
395 mat._origin = vposition;
396 collisionObject.SetWorldTransform(mat);
397
398 }
399
400 public override Vector3 GetPosition(BulletBody pCollisionObject)
401 {
402 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
403 IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin;
404 return new Vector3(pos.X, pos.Y, pos.Z);
405 }
406
407 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
408 {
409 CollisionShape shape = (pShape as BulletShapeXNA).shape;
410 IndexedVector3 inertia = IndexedVector3.Zero;
411 shape.CalculateLocalInertia(pphysMass, out inertia);
412 return new Vector3(inertia.X, inertia.Y, inertia.Z);
413 }
414
415 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
416 {
417 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
418 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
419 body.SetMassProps(pphysMass, inertia);
420 }
421
422
423 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
424 {
425 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
426 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
427 body.SetTotalForce(ref force);
428 }
429
430 public override void SetFriction(BulletBody pCollisionObject, float _currentFriction)
431 {
432 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
433 collisionObject.SetFriction(_currentFriction);
434 }
435
436 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
437 {
438 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
439 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
440 body.SetLinearVelocity(velocity);
441 }
442
443 public override void Activate(BulletBody pCollisionObject, bool pforceactivation)
444 {
445 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
446 collisionObject.Activate(pforceactivation);
447
448 }
449
450 public override Quaternion GetOrientation(BulletBody pCollisionObject)
451 {
452 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
453 IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation();
454 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
455 }
456
457 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
458 {
459 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
460 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
461 existingcollisionFlags &= ~pcollisionFlags;
462 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
463 return (CollisionFlags)(uint)existingcollisionFlags;
464 }
465
466 public override float GetCcdMotionThreshold(BulletBody pCollisionObject)
467 {
468 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
469 return collisionObject.GetCcdSquareMotionThreshold();
470 }
471
472 public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject)
473 {
474 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
475 return collisionObject.GetCcdSweptSphereRadius();
476
477 }
478
479 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
480 {
481 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
482 return (IntPtr)shape.GetUserPointer();
483 }
484
485 public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val)
486 {
487 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
488 shape.SetUserPointer(val);
489 }
490
491 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
492 {
493 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
494 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
495 body.SetGravity(gravity);
496 }
497
498 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
499 {
500 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
501 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
502 world.RemoveConstraint(constraint);
503 return true;
504 }
505
506 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
507 {
508 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
509 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
510 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
511 constraint.SetLinearLowerLimit(lowlimit);
512 constraint.SetLinearUpperLimit(highlimit);
513 return true;
514 }
515
516 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
517 {
518 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
519 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
520 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
521 constraint.SetAngularLowerLimit(lowlimit);
522 constraint.SetAngularUpperLimit(highlimit);
523 return true;
524 }
525
526 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
527 {
528 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
529 constraint.SetOverrideNumSolverIterations((int)cnt);
530 }
531
532 public override bool CalculateTransforms(BulletConstraint pConstraint)
533 {
534 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
535 constraint.CalculateTransforms();
536 return true;
537 }
538
539 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
540 {
541 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
542 constraint.SetEnabled((p_2 == 0) ? false : true);
543 }
544
545
546 //BulletSimAPI.Create6DofConstraint(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
547 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
548
549 {
550 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
551 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
552 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
553 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
554 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
555 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
556 frame1._origin = frame1v;
557
558 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
559 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
560 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
561 frame2._origin = frame1v;
562
563 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
564 puseLinearReferenceFrameA);
565 consttr.CalculateTransforms();
566 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
567
568 return new BulletConstraintXNA(consttr);
569 }
570
571
572 /// <summary>
573 ///
574 /// </summary>
575 /// <param name="pWorld"></param>
576 /// <param name="pBody1"></param>
577 /// <param name="pBody2"></param>
578 /// <param name="pjoinPoint"></param>
579 /// <param name="puseLinearReferenceFrameA"></param>
580 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
581 /// <returns></returns>
582 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
583 {
584 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
585 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
586 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
587 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
588 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
589
590 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
591 IndexedMatrix mat = IndexedMatrix.Identity;
592 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
593 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
594 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
595
596 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
597 consttr.CalculateTransforms();
598 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
599
600 return new BulletConstraintXNA(consttr);
601 }
602 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
603 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
604 {
605 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
606 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
607 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
608 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
609 frame1._origin = frame1v;
610
611 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
612 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
613 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
614 frame2._origin = frame1v;
615 constraint.SetFrames(ref frame1, ref frame2);
616 return true;
617 }
618
619 public override Vector3 GetLinearVelocity(BulletBody pBody)
620 {
621 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
622 IndexedVector3 iv3 = body.GetLinearVelocity();
623 return new Vector3(iv3.X, iv3.Y, iv3.Z);
624 }
625 public override Vector3 GetAngularVelocity(BulletBody pBody)
626 {
627 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
628 IndexedVector3 iv3 = body.GetAngularVelocity();
629 return new Vector3(iv3.X, iv3.Y, iv3.Z);
630 }
631 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
632 {
633 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
634 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
635 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
636 return new Vector3(iv3.X, iv3.Y, iv3.Z);
637 }
638 public override void Translate(BulletBody pCollisionObject, Vector3 trans)
639 {
640 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
641 collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z));
642 }
643 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
644 {
645 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
646 body.UpdateDeactivation(timeStep);
647 }
648
649 public override bool WantsSleeping(BulletBody pBody)
650 {
651 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
652 return body.WantsSleeping();
653 }
654
655 public override void SetAngularFactor(BulletBody pBody, float factor)
656 {
657 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
658 body.SetAngularFactor(factor);
659 }
660
661 public override Vector3 GetAngularFactor(BulletBody pBody)
662 {
663 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
664 IndexedVector3 iv3 = body.GetAngularFactor();
665 return new Vector3(iv3.X, iv3.Y, iv3.Z);
666 }
667
668 public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject)
669 {
670 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
671 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
672 return world.IsInWorld(collisionObject);
673 }
674
675 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
676 {
677 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
678 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
679 body.AddConstraintRef(constrain);
680 }
681
682 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
683 {
684 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
685 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
686 body.RemoveConstraintRef(constrain);
687 }
688
689 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
690 {
691 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
692 return new BulletConstraintXNA(body.GetConstraintRef(index));
693 }
694
695 public override int GetNumConstraintRefs(BulletBody pBody)
696 {
697 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
698 return body.GetNumConstraintRefs();
699 }
700
701 public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity)
702 {
703 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
704 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
705 collisionObject.SetInterpolationLinearVelocity(ref velocity);
706 }
707
708 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
709 {
710 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
711 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
712 return true;
713 }
714 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
715 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
716 {
717 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
718 constraint.SetBreakingImpulseThreshold(threshold);
719 return true;
720 }
721 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
722 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
723 {
724 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
725 float lineardamping = body.GetLinearDamping();
726 body.SetDamping(lineardamping, angularDamping);
727
728 }
729
730 public override void UpdateInertiaTensor(BulletBody pBody)
731 {
732 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
733 body.UpdateInertiaTensor();
734 }
735
736 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
737 {
738 CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
739 shape.RecalculateLocalAabb();
740 }
741
742 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
743 public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject)
744 {
745 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
746 uint flags = (uint)collisionObject.GetCollisionFlags();
747 return (CollisionFlags) flags;
748 }
749
750 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
751 {
752 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
753 body.SetDamping(pLinear, pAngular);
754 }
755 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
756 public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime)
757 {
758 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
759 collisionObject.SetDeactivationTime(pDeactivationTime);
760 }
761 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
762 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
763 {
764 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
765 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
766 }
767
768 public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject)
769 {
770 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
771 return (CollisionObjectTypes)(int) collisionObject.GetInternalType();
772 }
773
774 public override void ApplyGravity(BulletBody pBody)
775 {
776
777 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
778 body.ApplyGravity();
779 }
780
781 public override Vector3 GetGravity(BulletBody pBody)
782 {
783 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
784 IndexedVector3 gravity = body.GetGravity();
785 return new Vector3(gravity.X, gravity.Y, gravity.Z);
786 }
787
788 public override void SetLinearDamping(BulletBody pBody, float lin_damping)
789 {
790 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
791 float angularDamping = body.GetAngularDamping();
792 body.SetDamping(lin_damping, angularDamping);
793 }
794
795 public override float GetLinearDamping(BulletBody pBody)
796 {
797 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
798 return body.GetLinearDamping();
799 }
800
801 public override float GetAngularDamping(BulletBody pBody)
802 {
803 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
804 return body.GetAngularDamping();
805 }
806
807 public override float GetLinearSleepingThreshold(BulletBody pBody)
808 {
809 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
810 return body.GetLinearSleepingThreshold();
811 }
812
813 public override void ApplyDamping(BulletBody pBody, float timeStep)
814 {
815 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
816 body.ApplyDamping(timeStep);
817 }
818
819 public override Vector3 GetLinearFactor(BulletBody pBody)
820 {
821 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
822 IndexedVector3 linearFactor = body.GetLinearFactor();
823 return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z);
824 }
825
826 public override void SetLinearFactor(BulletBody pBody, Vector3 factor)
827 {
828 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
829 body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z));
830 }
831
832 public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot)
833 {
834 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
835 IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W);
836 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat);
837 mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z);
838 body.SetCenterOfMassTransform( ref mat);
839 /* TODO: double check this */
840 }
841
842 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
843 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
844 {
845 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
846 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
847 body.ApplyCentralForce(ref fSum);
848 }
849 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
850 {
851 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
852 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
853 body.ApplyCentralImpulse(ref fSum);
854 }
855 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
856 {
857 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
858 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
859 body.ApplyTorque(ref fSum);
860 }
861 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
862 {
863 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
864 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
865 body.ApplyTorqueImpulse(ref fSum);
866 }
867
868 public override void DestroyObject(BulletWorld pWorld, BulletBody pBody)
869 {
870 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
871 CollisionObject co = (pBody as BulletBodyXNA).rigidBody;
872 RigidBody bo = co as RigidBody;
873 if (bo == null)
874 {
875
876 if (world.IsInWorld(co))
877 {
878 world.RemoveCollisionObject(co);
879 }
880 }
881 else
882 {
883
884 if (world.IsInWorld(bo))
885 {
886 world.RemoveRigidBody(bo);
887 }
888 }
889
890 }
891
892 public override void Shutdown(BulletWorld pWorld)
893 {
894 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
895 world.Cleanup();
896 }
897
898 public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id)
899 {
900 CollisionShape shape1 = (pShape as BulletShapeXNA).shape;
901
902 // TODO: Turn this from a reference copy to a Value Copy.
903 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSPhysicsShapeType.SHAPE_UNKNOWN);
904
905 return shape2;
906 }
907
908 public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape)
909 {
910 //TODO:
911 return false;
912 }
913 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
914
915 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
916 {
917 CollisionWorld world = (pWorld as BulletWorldXNA).world;
918 IndexedMatrix mat =
919 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
920 pRawOrientation.Z, pRawOrientation.W));
921 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
922 CollisionShape shape = (pShape as BulletShapeXNA).shape;
923 //UpdateSingleAabb(world, shape);
924 // TODO: Feed Update array into null
925 SimMotionState motionState = new SimMotionState(world, pLocalID, mat, null);
926 RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero);
927 RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, new SimMotionState(world, pLocalID, mat, null),shape,IndexedVector3.Zero)
928 {
929 m_mass = 0
930 };
931 /*
932 m_mass = mass;
933 m_motionState =motionState;
934 m_collisionShape = collisionShape;
935 m_localInertia = localInertia;
936 m_linearDamping = 0f;
937 m_angularDamping = 0f;
938 m_friction = 0.5f;
939 m_restitution = 0f;
940 m_linearSleepingThreshold = 0.8f;
941 m_angularSleepingThreshold = 1f;
942 m_additionalDamping = false;
943 m_additionalDampingFactor = 0.005f;
944 m_additionalLinearDampingThresholdSqr = 0.01f;
945 m_additionalAngularDampingThresholdSqr = 0.01f;
946 m_additionalAngularDampingFactor = 0.01f;
947 m_startWorldTransform = IndexedMatrix.Identity;
948 */
949 body.SetUserPointer(pLocalID);
950
951 return new BulletBodyXNA(pLocalID, body);
952 }
953
954
955 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
956 {
957
958 IndexedMatrix mat =
959 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
960 pRawOrientation.Z, pRawOrientation.W));
961 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
962
963 CollisionShape shape = (pShape as BulletShapeXNA).shape;
964
965 // TODO: Feed Update array into null
966 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
967 body.SetWorldTransform(mat);
968 body.SetUserPointer(pLocalID);
969 return new BulletBodyXNA(pLocalID, body);
970 }
971 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
972 public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags)
973 {
974 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
975 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
976 return (CollisionFlags)collisionObject.GetCollisionFlags();
977 }
978
979 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
980 {
981
982 /* TODO */
983 return Vector3.Zero;
984 }
985 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
986 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
987 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
988 public override bool IsStaticObject(BulletBody pCollisionObject)
989 {
990 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
991 return collisionObject.IsStaticObject();
992
993 }
994 public override bool IsKinematicObject(BulletBody pCollisionObject)
995 {
996 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
997 return collisionObject.IsKinematicObject();
998 }
999 public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject)
1000 {
1001 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1002 return collisionObject.IsStaticOrKinematicObject();
1003 }
1004 public override bool HasContactResponse(BulletBody pCollisionObject)
1005 {
1006 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1007 return collisionObject.HasContactResponse();
1008 }
1009 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
1010 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
1011 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
1012 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
1013 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
1014 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
1015 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
1016 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
1017
1018 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
1019 public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction)
1020 {
1021 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1022 collisionObject.SetHitFraction(pHitFraction);
1023 }
1024 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
1025 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
1026 {
1027 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1028 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
1029 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
1030 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
1031 capsuleShapeZ.SetLocalScaling(ref scale);
1032
1033 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
1034 }
1035
1036 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
1037 int maxCollisions, ref CollisionDesc[] collisionArray,
1038 int maxUpdates, ref EntityProperties[] updateArray
1039 )
1040 {
1041
1042 m_updateArray = updateArray;
1043 m_collisionArray = collisionArray;
1044 /* TODO */
1045 ConfigurationParameters[] configparms = new ConfigurationParameters[1];
1046 configparms[0] = parms;
1047 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
1048 m_maxCollisions = maxCollisions;
1049 m_maxUpdatesPerFrame = maxUpdates;
1050
1051
1052 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1053 }
1054
1055 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1056 ConfigurationParameters[] o,
1057 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1058 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1059 object mDebugLogCallbackHandle)
1060 {
1061 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
1062
1063 p.angularDamping = o[0].XangularDamping;
1064 p.defaultFriction = o[0].defaultFriction;
1065 p.defaultFriction = o[0].defaultFriction;
1066 p.defaultDensity = o[0].defaultDensity;
1067 p.defaultRestitution = o[0].defaultRestitution;
1068 p.collisionMargin = o[0].collisionMargin;
1069 p.gravity = o[0].gravity;
1070
1071 p.linearDamping = o[0].XlinearDamping;
1072 p.angularDamping = o[0].XangularDamping;
1073 p.deactivationTime = o[0].XdeactivationTime;
1074 p.linearSleepingThreshold = o[0].XlinearSleepingThreshold;
1075 p.angularSleepingThreshold = o[0].XangularSleepingThreshold;
1076 p.ccdMotionThreshold = o[0].XccdMotionThreshold;
1077 p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius;
1078 p.contactProcessingThreshold = o[0].XcontactProcessingThreshold;
1079
1080 p.terrainImplementation = o[0].XterrainImplementation;
1081 p.terrainFriction = o[0].XterrainFriction;
1082
1083 p.terrainHitFraction = o[0].XterrainHitFraction;
1084 p.terrainRestitution = o[0].XterrainRestitution;
1085 p.terrainCollisionMargin = o[0].XterrainCollisionMargin;
1086
1087 p.avatarFriction = o[0].XavatarFriction;
1088 p.avatarStandingFriction = o[0].XavatarStandingFriction;
1089 p.avatarDensity = o[0].XavatarDensity;
1090 p.avatarRestitution = o[0].XavatarRestitution;
1091 p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth;
1092 p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth;
1093 p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight;
1094 p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold;
1095
1096 p.vehicleAngularDamping = o[0].XvehicleAngularDamping;
1097
1098 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1099 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1100 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
1101 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
1102 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
1103 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
1104 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
1105 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
1106
1107 p.linksetImplementation = o[0].XlinksetImplementation;
1108 p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset;
1109 p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor;
1110 p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel;
1111 p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce;
1112 p.linkConstraintERP = o[0].XlinkConstraintERP;
1113 p.linkConstraintCFM = o[0].XlinkConstraintCFM;
1114 p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations;
1115 p.physicsLoggingFrames = o[0].XphysicsLoggingFrames;
1116 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1117
1118 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1119 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1120
1121
1122 if (p.maxPersistantManifoldPoolSize > 0)
1123 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
1124 if (p.shouldDisableContactPoolDynamicAllocation !=0)
1125 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
1126 //if (p.maxCollisionAlgorithmPoolSize >0 )
1127
1128 DbvtBroadphase m_broadphase = new DbvtBroadphase();
1129 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
1130 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
1131
1132 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
1133 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
1134
1135 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
1136
1137 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
1138
1139
1140 world.UpdatedObjects = BSAPIXNA.GetBulletXNAEntityStruct(BSAPIXNA.BulletSimEntityStructToByteArray(updateArray, updateArray.Length));
1141 world.UpdatedCollisions = BSAPIXNA.GetBulletXNACollisionStruct(BSAPIXNA.BulletSimCollisionStructToByteArray(collisionArray, collisionArray.Length));
1142 world.LastCollisionDesc = 0;
1143 world.LastEntityProperty = 0;
1144
1145 world.WorldSettings.Params = p;
1146 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
1147 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
1148 if (p.shouldRandomizeSolverOrder != 0)
1149 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
1150
1151 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
1152 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
1153
1154 if (p.shouldEnableFrictionCaching != 0)
1155 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1156
1157 if (p.numberOfSolverIterations > 0)
1158 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
1159
1160
1161 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
1162 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
1163 world.GetSolverInfo().m_globalCfm = 0.0f;
1164 world.GetSolverInfo().m_tau = 0.6f;
1165 world.GetSolverInfo().m_friction = 0.3f;
1166 world.GetSolverInfo().m_maxErrorReduction = 20f;
1167 world.GetSolverInfo().m_numIterations = 10;
1168 world.GetSolverInfo().m_erp = 0.2f;
1169 world.GetSolverInfo().m_erp2 = 0.1f;
1170 world.GetSolverInfo().m_sor = 1.0f;
1171 world.GetSolverInfo().m_splitImpulse = false;
1172 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1173 world.GetSolverInfo().m_linearSlop = 0.0f;
1174 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1175 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1176 world.SetForceUpdateAllAabbs(true);
1177
1178 //BSParam.TerrainImplementation = 0;
1179 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1180
1181 return world;
1182 }
1183 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1184 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1185 {
1186 Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
1187 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1188 {
1189 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1190 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1191 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1192 }
1193 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1194 {
1195 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1196 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1197 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1198 }
1199 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1200 {
1201 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1202 }
1203 return true;
1204 }
1205
1206 public override bool PushUpdate(BulletBody pCollisionObject)
1207 {
1208 bool ret = false;
1209 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1210 RigidBody rb = collisionObject as RigidBody;
1211 if (rb != null)
1212 {
1213 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1214 if (sms != null)
1215 {
1216 IndexedMatrix wt = IndexedMatrix.Identity;
1217 sms.GetWorldTransform(out wt);
1218 sms.SetWorldTransform(ref wt, true);
1219 ret = true;
1220 }
1221 }
1222 return ret;
1223
1224 }
1225
1226 public override float GetAngularMotionDisc(BulletShape pShape)
1227 {
1228 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1229 return shape.GetAngularMotionDisc();
1230 }
1231 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1232 {
1233 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1234 return shape.GetContactBreakingThreshold(defaultFactor);
1235 }
1236 public override bool IsCompound(BulletShape pShape)
1237 {
1238 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1239 return shape.IsCompound();
1240 }
1241 public override bool IsSoftBody(BulletShape pShape)
1242 {
1243 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1244 return shape.IsSoftBody();
1245 }
1246 public override bool IsPolyhedral(BulletShape pShape)
1247 {
1248 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1249 return shape.IsPolyhedral();
1250 }
1251 public override bool IsConvex2d(BulletShape pShape)
1252 {
1253 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1254 return shape.IsConvex2d();
1255 }
1256 public override bool IsConvex(BulletShape pShape)
1257 {
1258 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1259 return shape.IsConvex();
1260 }
1261 public override bool IsNonMoving(BulletShape pShape)
1262 {
1263 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1264 return shape.IsNonMoving();
1265 }
1266 public override bool IsConcave(BulletShape pShape)
1267 {
1268 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1269 return shape.IsConcave();
1270 }
1271 public override bool IsInfinite(BulletShape pShape)
1272 {
1273 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1274 return shape.IsInfinite();
1275 }
1276 public override bool IsNativeShape(BulletShape pShape)
1277 {
1278 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1279 bool ret;
1280 switch (shape.GetShapeType())
1281 {
1282 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1283 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1284 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1285 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1286 ret = true;
1287 break;
1288 default:
1289 ret = false;
1290 break;
1291 }
1292 return ret;
1293 }
1294
1295 public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin)
1296 {
1297 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1298 shape.SetMargin(pMargin);
1299 }
1300
1301 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1302 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1303 {
1304 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1305 IndexedMatrix bodyTransform = new IndexedMatrix();
1306 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1307 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1308 GhostObject gObj = new PairCachingGhostObject();
1309 gObj.SetWorldTransform(bodyTransform);
1310 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1311 gObj.SetCollisionShape(shape);
1312 gObj.SetUserPointer(pLocalID);
1313 // TODO: Add to Special CollisionObjects!
1314 return new BulletBodyXNA(pLocalID, gObj);
1315 }
1316
1317 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape)
1318 {
1319 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1320 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1321 if (pShape == null)
1322 {
1323 collisionObject.SetCollisionShape(new EmptyShape());
1324 }
1325 else
1326 {
1327 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1328 collisionObject.SetCollisionShape(shape);
1329 }
1330 }
1331 public override BulletShape GetCollisionShape(BulletBody pCollisionObject)
1332 {
1333 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1334 CollisionShape shape = collisionObject.GetCollisionShape();
1335 return new BulletShapeXNA(shape,BSPhysicsShapeType.SHAPE_UNKNOWN);
1336 }
1337
1338 //(PhysicsScene.World.ptr, nativeShapeData)
1339 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1340 {
1341 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1342 CollisionShape shape = null;
1343 switch (pShapeData.Type)
1344 {
1345 case BSPhysicsShapeType.SHAPE_BOX:
1346 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1347 break;
1348 case BSPhysicsShapeType.SHAPE_CONE:
1349 shape = new ConeShapeZ(0.5f, 1.0f);
1350 break;
1351 case BSPhysicsShapeType.SHAPE_CYLINDER:
1352 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1353 break;
1354 case BSPhysicsShapeType.SHAPE_SPHERE:
1355 shape = new SphereShape(0.5f);
1356 break;
1357
1358 }
1359 if (shape != null)
1360 {
1361 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1362 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1363 shape.SetLocalScaling(ref scaling);
1364
1365 }
1366 return new BulletShapeXNA(shape, pShapeData.Type);
1367 }
1368 //PhysicsScene.World.ptr, false
1369 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1370 {
1371 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1372 }
1373
1374 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1375 {
1376 CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
1377 return compoundshape.GetNumChildShapes();
1378 }
1379 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1380 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1381 {
1382 IndexedMatrix relativeTransform = new IndexedMatrix();
1383 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1384 CollisionShape addshape = (paddShape as BulletShapeXNA).shape;
1385
1386 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1387 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1388 compoundshape.AddChildShape(ref relativeTransform, addshape);
1389
1390 }
1391
1392 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1393 {
1394 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1395 CollisionShape ret = null;
1396 ret = compoundshape.GetChildShape(pii);
1397 compoundshape.RemoveChildShapeByIndex(pii);
1398 return new BulletShapeXNA(ret, BSPhysicsShapeType.SHAPE_UNKNOWN);
1399 }
1400
1401 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { /* TODO */ return null; }
1402 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1403 public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ }
1404
1405 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1406 {
1407 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1408 m_planeshape.SetMargin(pcollisionMargin);
1409 m_planeshape.SetUserPointer(pLocalId);
1410 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1411 }
1412
1413 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1414 {
1415 HingeConstraint constrain = null;
1416 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1417 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1418 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1419 if (rb1 != null && rb2 != null)
1420 {
1421 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1422 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1423 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1424 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1425 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1426 }
1427 return new BulletConstraintXNA(constrain);
1428 }
1429
1430 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
1431 {
1432 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1433 CompoundShape compoundshape = new CompoundShape(false);
1434
1435 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1436 int ii = 1;
1437
1438 for (int i = 0; i < pHullCount; i++)
1439 {
1440 int vertexCount = (int) pConvHulls[ii];
1441
1442 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1443 IndexedMatrix childTrans = IndexedMatrix.Identity;
1444 childTrans._origin = centroid;
1445
1446 List<IndexedVector3> virts = new List<IndexedVector3>();
1447 int ender = ((ii + 4) + (vertexCount*3));
1448 for (int iii = ii + 4; iii < ender; iii+=3)
1449 {
1450
1451 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1452 }
1453 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1454 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1455 compoundshape.AddChildShape(ref childTrans, convexShape);
1456 ii += (vertexCount*3 + 4);
1457 }
1458
1459 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1460 }
1461
1462 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
1463 {
1464 /* TODO */ return null;
1465
1466 }
1467
1468 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1469 {
1470 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1471
1472 for (int iter = 0; iter < pVerticesCount; iter++)
1473 {
1474 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1475 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1476 }
1477
1478 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1479 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1480 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1481 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1482 IndexedMesh mesh = new IndexedMesh();
1483 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1484 mesh.m_numTriangles = pIndicesCount/3;
1485 mesh.m_numVertices = pVerticesCount;
1486 mesh.m_triangleIndexBase = indicesarr;
1487 mesh.m_vertexBase = vertices;
1488 mesh.m_vertexStride = 3;
1489 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1490 mesh.m_triangleIndexStride = 3;
1491
1492 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1493 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1494 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1495 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1496 // world.UpdateSingleAabb(meshShape);
1497 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1498
1499 }
1500 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1501 {
1502
1503 String fileName = "objTest3.raw";
1504 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1505 StreamWriter sw = new StreamWriter(completePath);
1506 IndexedMesh mesh = new IndexedMesh();
1507
1508 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1509 mesh.m_numTriangles = pIndicesCount / 3;
1510 mesh.m_numVertices = pVerticesCount;
1511 mesh.m_triangleIndexBase = indices;
1512 mesh.m_vertexBase = vertices;
1513 mesh.m_vertexStride = 3;
1514 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1515 mesh.m_triangleIndexStride = 3;
1516
1517 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1518 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1519
1520
1521
1522 for (int i = 0; i < pVerticesCount; i++)
1523 {
1524
1525 string s = vertices[indices[i * 3]].ToString("0.0000");
1526 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1527 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1528
1529 sw.Write(s + "\n");
1530 }
1531
1532 sw.Close();
1533 }
1534 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1535 {
1536
1537 String fileName = "objTest6.raw";
1538 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1539 StreamWriter sw = new StreamWriter(completePath);
1540 IndexedMesh mesh = new IndexedMesh();
1541
1542 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1543 mesh.m_numTriangles = pIndicesCount / 3;
1544 mesh.m_numVertices = pVerticesCount;
1545 mesh.m_triangleIndexBase = indices;
1546 mesh.m_vertexBase = vertices;
1547 mesh.m_vertexStride = 3;
1548 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1549 mesh.m_triangleIndexStride = 3;
1550
1551 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1552 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1553
1554
1555 sw.WriteLine("Indices");
1556 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1557 for (int iter = 0; iter < indices.Length; iter++)
1558 {
1559 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1560 }
1561 sw.WriteLine("VerticesFloats");
1562 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1563 for (int iter = 0; iter < vertices.Length; iter++)
1564 {
1565 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1566 }
1567
1568 // for (int i = 0; i < pVerticesCount; i++)
1569 // {
1570 //
1571 // string s = vertices[indices[i * 3]].ToString("0.0000");
1572 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1573 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1574 //
1575 // sw.Write(s + "\n");
1576 //}
1577
1578 sw.Close();
1579 }
1580
1581 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1582 float scaleFactor, float collisionMargin)
1583 {
1584 const int upAxis = 2;
1585 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
1586 heightMap, scaleFactor,
1587 minHeight, maxHeight, upAxis,
1588 false);
1589 terrainShape.SetMargin(collisionMargin + 0.5f);
1590 terrainShape.SetUseDiamondSubdivision(true);
1591 terrainShape.SetUserPointer(id);
1592 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
1593 }
1594
1595 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1596 {
1597 TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain;
1598 bool onOff = ponOff != 0;
1599 bool ret = false;
1600
1601 switch (tconstrain.GetConstraintType())
1602 {
1603 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1604 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
1605 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1606 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1607 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1608 ret = true;
1609 break;
1610 }
1611
1612
1613 return ret;
1614
1615 }
1616
1617 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
1618 out int updatedEntityCount, out int collidersCount)
1619 {
1620 /* TODO */
1621 updatedEntityCount = 0;
1622 collidersCount = 0;
1623
1624
1625 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
1626
1627 return ret;
1628 }
1629
1630 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1631 out int updatedEntityCount, out EntityProperties[] updatedEntities,
1632 out int collidersCount, out CollisionDesc[] colliders)
1633 {
1634 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1635 out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame);
1636 return epic;
1637 }
1638
1639 private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
1640 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
1641 {
1642 int numSimSteps = 0;
1643
1644 updatedEntityCount = 0;
1645 collidersCount = 0;
1646
1647
1648 if (pWorld is BulletWorldXNA)
1649 {
1650 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1651
1652 world.LastCollisionDesc = 0;
1653 world.LastEntityProperty = 0;
1654 world.UpdatedObjects = new BulletXNA.EntityProperties[maxUpdates];
1655 world.UpdatedCollisions = new BulletXNA.CollisionDesc[maxCollisions];
1656 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1657 int updates = 0;
1658
1659
1660
1661
1662 m_collisionsThisFrame = 0;
1663 int numManifolds = world.GetDispatcher().GetNumManifolds();
1664 for (int j = 0; j < numManifolds; j++)
1665 {
1666 PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1667 int numContacts = contactManifold.GetNumContacts();
1668 if (numContacts == 0)
1669 continue;
1670
1671 CollisionObject objA = contactManifold.GetBody0() as CollisionObject;
1672 CollisionObject objB = contactManifold.GetBody1() as CollisionObject;
1673
1674 ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0);
1675 IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
1676 IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
1677
1678 RecordCollision(world, objA, objB, contactPoint, contactNormal);
1679 m_collisionsThisFrame ++;
1680 if (m_collisionsThisFrame >= 9999999)
1681 break;
1682
1683
1684 }
1685
1686 updatedEntityCount = world.LastEntityProperty;
1687 updatedEntities = GetBulletSimEntityStruct(BulletXNAEntityStructToByteArray(world.UpdatedObjects, world.LastEntityProperty));
1688
1689
1690
1691
1692 collidersCount = world.LastCollisionDesc;
1693 colliders =
1694 GetBulletSimCollisionStruct(BulletXNACollisionStructToByteArray(world.UpdatedCollisions, world.LastCollisionDesc));//new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1695
1696 }
1697 else
1698 {
1699 //if (updatedEntities is null)
1700 //updatedEntities = new List<BulletXNA.EntityProperties>();
1701 //updatedEntityCount = 0;
1702 //if (colliders is null)
1703 //colliders = new List<BulletXNA.CollisionDesc>();
1704 //collidersCount = 0;
1705
1706 updatedEntities = new EntityProperties[0];
1707
1708
1709 colliders = new CollisionDesc[0];
1710
1711 }
1712 return numSimSteps;
1713 }
1714
1715 private static void RecordCollision(CollisionWorld world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm)
1716 {
1717
1718 IndexedVector3 contactNormal = norm;
1719 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
1720 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
1721 {
1722 return;
1723 }
1724 uint idA = (uint)objA.GetUserPointer();
1725 uint idB = (uint)objB.GetUserPointer();
1726 if (idA > idB)
1727 {
1728 uint temp = idA;
1729 idA = idB;
1730 idB = temp;
1731 contactNormal = -contactNormal;
1732 }
1733
1734 ulong collisionID = ((ulong) idA << 32) | idB;
1735
1736 BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc()
1737 {
1738 aID = idA,
1739 bID = idB,
1740 point = contact,
1741 normal = contactNormal
1742 };
1743 if (world.LastCollisionDesc < world.UpdatedCollisions.Length)
1744 world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc);
1745 m_collisionsThisFrame++;
1746
1747
1748 }
1749 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject)
1750 {
1751 EntityProperties ent = new EntityProperties();
1752 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1753 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1754 IndexedMatrix transform = collisionObject.GetWorldTransform();
1755 IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity();
1756 IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity();
1757 IndexedQuaternion rotation = transform.GetRotation();
1758 ent.Acceleration = Vector3.Zero;
1759 ent.ID = (uint)collisionObject.GetUserPointer();
1760 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
1761 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
1762 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
1763 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
1764 return ent;
1765 }
1766
1767 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ return false; }
1768
1769 public override Vector3 GetLocalScaling(BulletShape pShape)
1770 {
1771 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1772 IndexedVector3 scale = shape.GetLocalScaling();
1773 return new Vector3(scale.X,scale.Y,scale.Z);
1774 }
1775
1776 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
1777 {
1778 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1779 if (world != null)
1780 {
1781 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
1782 {
1783 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
1784
1785 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
1786 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
1787 using (
1788 ClosestNotMeRayResultCallback rayCallback =
1789 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
1790 )
1791 {
1792 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
1793 if (rayCallback.HasHit())
1794 {
1795 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
1796 }
1797 return rayCallback.HasHit();
1798 }
1799 }
1800 }
1801 return false;
1802 }
1803
1804 public static unsafe BulletXNA.CollisionDesc[] GetBulletXNACollisionStruct(byte[] buffer)
1805 {
1806 int count = buffer.Length/sizeof (BulletXNA.CollisionDesc);
1807 BulletXNA.CollisionDesc[] result = new BulletXNA.CollisionDesc[count];
1808 BulletXNA.CollisionDesc* ptr;
1809 fixed (byte* localBytes = new byte[buffer.Length])
1810 {
1811 for (int i = 0; i < buffer.Length; i++)
1812 {
1813 localBytes[i] = buffer[i];
1814 }
1815 for (int i=0;i<count;i++)
1816 {
1817 ptr = (BulletXNA.CollisionDesc*) (localBytes + sizeof (BulletXNA.CollisionDesc)*i);
1818 result[i] = new BulletXNA.CollisionDesc();
1819 result[i] = *ptr;
1820 }
1821 }
1822 return result;
1823 }
1824
1825 public static unsafe CollisionDesc[] GetBulletSimCollisionStruct(byte[] buffer)
1826 {
1827 int count = buffer.Length / sizeof(CollisionDesc);
1828 CollisionDesc[] result = new CollisionDesc[count];
1829 CollisionDesc* ptr;
1830 fixed (byte* localBytes = new byte[buffer.Length])
1831 {
1832 for (int i = 0; i < buffer.Length; i++)
1833 {
1834 localBytes[i] = buffer[i];
1835 }
1836 for (int i = 0; i < count; i++)
1837 {
1838 ptr = (CollisionDesc*)(localBytes + sizeof(CollisionDesc) * i);
1839 result[i] = new CollisionDesc();
1840 result[i] = *ptr;
1841 }
1842 }
1843 return result;
1844 }
1845 public static unsafe byte[] BulletSimCollisionStructToByteArray(CollisionDesc[] CollisionDescArray, int count)
1846 {
1847 int arrayLength = CollisionDescArray.Length > count ? count : CollisionDescArray.Length;
1848 byte[] byteArray = new byte[sizeof(CollisionDesc) * arrayLength];
1849 fixed (CollisionDesc* floatPointer = CollisionDescArray)
1850 {
1851 fixed (byte* bytePointer = byteArray)
1852 {
1853 CollisionDesc* read = floatPointer;
1854 CollisionDesc* write = (CollisionDesc*)bytePointer;
1855 for (int i = 0; i < arrayLength; i++)
1856 {
1857 *write++ = *read++;
1858 }
1859 }
1860 }
1861 return byteArray;
1862 }
1863 public static unsafe byte[] BulletXNACollisionStructToByteArray(BulletXNA.CollisionDesc[] CollisionDescArray, int count)
1864 {
1865 int arrayLength = CollisionDescArray.Length > count ? count : CollisionDescArray.Length;
1866 byte[] byteArray = new byte[sizeof(BulletXNA.CollisionDesc) * arrayLength];
1867 fixed (BulletXNA.CollisionDesc* floatPointer = CollisionDescArray)
1868 {
1869 fixed (byte* bytePointer = byteArray)
1870 {
1871 BulletXNA.CollisionDesc* read = floatPointer;
1872 BulletXNA.CollisionDesc* write = (BulletXNA.CollisionDesc*)bytePointer;
1873 for (int i = 0; i < arrayLength; i++)
1874 {
1875 *write++ = *read++;
1876 }
1877 }
1878 }
1879 return byteArray;
1880 }
1881 public static unsafe BulletXNA.EntityProperties[] GetBulletXNAEntityStruct(byte[] buffer)
1882 {
1883 int count = buffer.Length / sizeof(BulletXNA.EntityProperties);
1884 BulletXNA.EntityProperties[] result = new BulletXNA.EntityProperties[count];
1885 BulletXNA.EntityProperties* ptr;
1886 fixed (byte* localBytes = new byte[buffer.Length])
1887 {
1888 for (int i = 0; i < buffer.Length; i++)
1889 {
1890 localBytes[i] = buffer[i];
1891 }
1892 for (int i = 0; i < count; i++)
1893 {
1894 ptr = (BulletXNA.EntityProperties*)(localBytes + sizeof(BulletXNA.EntityProperties) * i);
1895 result[i] = new BulletXNA.EntityProperties();
1896 result[i] = *ptr;
1897 }
1898 }
1899 return result;
1900 }
1901
1902 public static unsafe EntityProperties[] GetBulletSimEntityStruct(byte[] buffer)
1903 {
1904 int count = buffer.Length / sizeof(EntityProperties);
1905 EntityProperties[] result = new EntityProperties[count];
1906 EntityProperties* ptr;
1907 fixed (byte* localBytes = new byte[buffer.Length])
1908 {
1909 for (int i = 0; i < buffer.Length; i++)
1910 {
1911 localBytes[i] = buffer[i];
1912 }
1913 for (int i = 0; i < count; i++)
1914 {
1915 ptr = (EntityProperties*)(localBytes + sizeof(EntityProperties) * i);
1916 result[i] = new EntityProperties();
1917 result[i] = *ptr;
1918 }
1919 }
1920 return result;
1921 }
1922 public static unsafe byte[] BulletSimEntityStructToByteArray(EntityProperties[] CollisionDescArray, int count)
1923 {
1924 int arrayLength = CollisionDescArray.Length > count ? count : CollisionDescArray.Length;
1925 byte[] byteArray = new byte[sizeof(EntityProperties) * arrayLength];
1926 fixed (EntityProperties* floatPointer = CollisionDescArray)
1927 {
1928 fixed (byte* bytePointer = byteArray)
1929 {
1930 EntityProperties* read = floatPointer;
1931 EntityProperties* write = (EntityProperties*)bytePointer;
1932 for (int i = 0; i < arrayLength; i++)
1933 {
1934 *write++ = *read++;
1935 }
1936 }
1937 }
1938 return byteArray;
1939 }
1940 public static unsafe byte[] BulletXNAEntityStructToByteArray(BulletXNA.EntityProperties[] CollisionDescArray, int count)
1941 {
1942 int arrayLength = CollisionDescArray.Length > count ? count : CollisionDescArray.Length;
1943 byte[] byteArray = new byte[sizeof(BulletXNA.EntityProperties) * arrayLength];
1944 fixed (BulletXNA.EntityProperties* floatPointer = CollisionDescArray)
1945 {
1946 fixed (byte* bytePointer = byteArray)
1947 {
1948 BulletXNA.EntityProperties* read = floatPointer;
1949 BulletXNA.EntityProperties* write = (BulletXNA.EntityProperties*)bytePointer;
1950 for (int i = 0; i < arrayLength; i++)
1951 {
1952 *write++ = *read++;
1953 }
1954 }
1955 }
1956 return byteArray;
1957 }
1958}
1959}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
new file mode 100644
index 0000000..f25b447
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -0,0 +1,688 @@
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 uint ID;
91 public BSPhysicsShapeType Type;
92 public Vector3 Position;
93 public Quaternion Rotation;
94 public Vector3 Velocity;
95 public Vector3 Scale;
96 public float Mass;
97 public float Buoyancy;
98 public System.UInt64 HullKey;
99 public System.UInt64 MeshKey;
100 public float Friction;
101 public float Restitution;
102 public float Collidable; // true of things bump into this
103 public float Static; // true if a static object. Otherwise gravity, etc.
104 public float Solid; // true if object cannot be passed through
105 public Vector3 Size;
106
107 // note that bools are passed as floats since bool size changes by language and architecture
108 public const float numericTrue = 1f;
109 public const float numericFalse = 0f;
110}
111[StructLayout(LayoutKind.Sequential)]
112public struct SweepHit
113{
114 public uint ID;
115 public float Fraction;
116 public Vector3 Normal;
117 public Vector3 Point;
118}
119[StructLayout(LayoutKind.Sequential)]
120public struct RaycastHit
121{
122 public uint ID;
123 public float Fraction;
124 public Vector3 Normal;
125}
126[StructLayout(LayoutKind.Sequential)]
127public struct CollisionDesc
128{
129 public uint aID;
130 public uint bID;
131 public Vector3 point;
132 public Vector3 normal;
133 public float penetration;
134}
135[StructLayout(LayoutKind.Sequential)]
136public struct EntityProperties
137{
138 public uint 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 XlinearDamping;
178 public float XangularDamping;
179 public float XdeactivationTime;
180 public float XlinearSleepingThreshold;
181 public float XangularSleepingThreshold;
182 public float XccdMotionThreshold;
183 public float XccdSweptSphereRadius;
184 public float XcontactProcessingThreshold;
185
186 public float XterrainImplementation;
187 public float XterrainFriction;
188 public float XterrainHitFraction;
189 public float XterrainRestitution;
190 public float XterrainCollisionMargin;
191
192 public float XavatarFriction;
193 public float XavatarStandingFriction;
194 public float XavatarDensity;
195 public float XavatarRestitution;
196 public float XavatarCapsuleWidth;
197 public float XavatarCapsuleDepth;
198 public float XavatarCapsuleHeight;
199 public float XavatarContactProcessingThreshold;
200
201 public float XvehicleAngularDamping;
202
203 public float maxPersistantManifoldPoolSize;
204 public float maxCollisionAlgorithmPoolSize;
205 public float shouldDisableContactPoolDynamicAllocation;
206 public float shouldForceUpdateAllAabbs;
207 public float shouldRandomizeSolverOrder;
208 public float shouldSplitSimulationIslands;
209 public float shouldEnableFrictionCaching;
210 public float numberOfSolverIterations;
211
212 public float XlinksetImplementation;
213 public float XlinkConstraintUseFrameOffset;
214 public float XlinkConstraintEnableTransMotor;
215 public float XlinkConstraintTransMotorMaxVel;
216 public float XlinkConstraintTransMotorMaxForce;
217 public float XlinkConstraintERP;
218 public float XlinkConstraintCFM;
219 public float XlinkConstraintSolverIterations;
220
221 public float XphysicsLoggingFrames;
222
223 public const float numericTrue = 1f;
224 public const float numericFalse = 0f;
225}
226
227
228// The states a bullet collision object can have
229public enum ActivationState : uint
230{
231 ACTIVE_TAG = 1,
232 ISLAND_SLEEPING,
233 WANTS_DEACTIVATION,
234 DISABLE_DEACTIVATION,
235 DISABLE_SIMULATION,
236}
237
238public enum CollisionObjectTypes : int
239{
240 CO_COLLISION_OBJECT = 1 << 0,
241 CO_RIGID_BODY = 1 << 1,
242 CO_GHOST_OBJECT = 1 << 2,
243 CO_SOFT_BODY = 1 << 3,
244 CO_HF_FLUID = 1 << 4,
245 CO_USER_TYPE = 1 << 5,
246}
247
248// Values used by Bullet and BulletSim to control object properties.
249// Bullet's "CollisionFlags" has more to do with operations on the
250// object (if collisions happen, if gravity effects it, ...).
251public enum CollisionFlags : uint
252{
253 CF_STATIC_OBJECT = 1 << 0,
254 CF_KINEMATIC_OBJECT = 1 << 1,
255 CF_NO_CONTACT_RESPONSE = 1 << 2,
256 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
257 CF_CHARACTER_OBJECT = 1 << 4,
258 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
259 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
260 // Following used by BulletSim to control collisions and updates
261 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
262 BS_FLOATS_ON_WATER = 1 << 11,
263 BS_VEHICLE_COLLISIONS = 1 << 12,
264 BS_NONE = 0,
265 BS_ALL = 0xFFFFFFFF
266};
267
268// Values f collisions groups and masks
269public enum CollisionFilterGroups : uint
270{
271 // Don't use the bit definitions!! Define the use in a
272 // filter/mask definition below. This way collision interactions
273 // are more easily found and debugged.
274 BNoneGroup = 0,
275 BDefaultGroup = 1 << 0, // 0001
276 BStaticGroup = 1 << 1, // 0002
277 BKinematicGroup = 1 << 2, // 0004
278 BDebrisGroup = 1 << 3, // 0008
279 BSensorTrigger = 1 << 4, // 0010
280 BCharacterGroup = 1 << 5, // 0020
281 BAllGroup = 0x000FFFFF,
282 // Filter groups defined by BulletSim
283 BGroundPlaneGroup = 1 << 10, // 0400
284 BTerrainGroup = 1 << 11, // 0800
285 BRaycastGroup = 1 << 12, // 1000
286 BSolidGroup = 1 << 13, // 2000
287 // BLinksetGroup = xx // a linkset proper is either static or dynamic
288 BLinksetChildGroup = 1 << 14, // 4000
289};
290
291// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
292// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
293public enum ConstraintParams : int
294{
295 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
296 BT_CONSTRAINT_STOP_ERP,
297 BT_CONSTRAINT_CFM,
298 BT_CONSTRAINT_STOP_CFM,
299};
300public enum ConstraintParamAxis : int
301{
302 AXIS_LINEAR_X = 0,
303 AXIS_LINEAR_Y,
304 AXIS_LINEAR_Z,
305 AXIS_ANGULAR_X,
306 AXIS_ANGULAR_Y,
307 AXIS_ANGULAR_Z,
308 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
309 AXIS_ANGULAR_ALL,
310 AXIS_ALL
311};
312
313public abstract class BSAPITemplate
314{
315// Returns the name of the underlying Bullet engine
316public abstract string BulletEngineName { get; }
317public abstract string BulletEngineVersion { get; protected set;}
318
319// Initialization and simulation
320public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
321 int maxCollisions, ref CollisionDesc[] collisionArray,
322 int maxUpdates, ref EntityProperties[] updateArray
323 );
324
325public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
326 out int updatedEntityCount, out int collidersCount);
327
328public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value);
329
330public abstract void Shutdown(BulletWorld sim);
331
332public abstract bool PushUpdate(BulletBody obj);
333
334// =====================================================================================
335// Mesh, hull, shape and body creation helper routines
336public abstract BulletShape CreateMeshShape(BulletWorld world,
337 int indicesCount, int[] indices,
338 int verticesCount, float[] vertices );
339
340public abstract BulletShape CreateHullShape(BulletWorld world,
341 int hullCount, float[] hulls);
342
343public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
344
345public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
346
347public abstract bool IsNativeShape(BulletShape shape);
348
349public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
350
351public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
352
353public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
354
355public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
356
357public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
358
359public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
360
361public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
362
363public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
364
365public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
366
367public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
368
369public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id);
370
371public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
372
373public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
374
375public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
376
377public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot);
378
379public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
380
381public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
382
383// =====================================================================================
384public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin);
385
386public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
387 float scaleFactor, float collisionMargin);
388
389// =====================================================================================
390// Constraint creation and helper routines
391public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
392 Vector3 frame1loc, Quaternion frame1rot,
393 Vector3 frame2loc, Quaternion frame2rot,
394 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
395
396public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
397 Vector3 joinPoint,
398 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
399
400public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
401 Vector3 pivotinA, Vector3 pivotinB,
402 Vector3 axisInA, Vector3 axisInB,
403 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
404
405public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
406
407public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
408
409public abstract bool SetFrames(BulletConstraint constrain,
410 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
411
412public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
413
414public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
415
416public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
417
418public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
419
420public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
421
422public abstract bool CalculateTransforms(BulletConstraint constrain);
423
424public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
425
426public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
427
428// =====================================================================================
429// btCollisionWorld entries
430public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
431
432public abstract void UpdateAabbs(BulletWorld world);
433
434public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
435
436public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
437
438// =====================================================================================
439// btDynamicsWorld entries
440// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
441public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
442
443public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
444
445public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
446
447public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
448// =====================================================================================
449// btCollisionObject entries
450public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
451
452public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
453
454public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
455
456public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
457
458public abstract float GetContactProcessingThreshold(BulletBody obj);
459
460public abstract bool IsStaticObject(BulletBody obj);
461
462public abstract bool IsKinematicObject(BulletBody obj);
463
464public abstract bool IsStaticOrKinematicObject(BulletBody obj);
465
466public abstract bool HasContactResponse(BulletBody obj);
467
468public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
469
470public abstract BulletShape GetCollisionShape(BulletBody obj);
471
472public abstract int GetActivationState(BulletBody obj);
473
474public abstract void SetActivationState(BulletBody obj, int state);
475
476public abstract void SetDeactivationTime(BulletBody obj, float dtime);
477
478public abstract float GetDeactivationTime(BulletBody obj);
479
480public abstract void ForceActivationState(BulletBody obj, ActivationState state);
481
482public abstract void Activate(BulletBody obj, bool forceActivation);
483
484public abstract bool IsActive(BulletBody obj);
485
486public abstract void SetRestitution(BulletBody obj, float val);
487
488public abstract float GetRestitution(BulletBody obj);
489
490public abstract void SetFriction(BulletBody obj, float val);
491
492public abstract float GetFriction(BulletBody obj);
493
494public abstract Vector3 GetPosition(BulletBody obj);
495
496public abstract Quaternion GetOrientation(BulletBody obj);
497
498public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
499
500// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
501
502// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
503
504public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
505
506public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
507
508public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
509
510public abstract float GetHitFraction(BulletBody obj);
511
512public abstract void SetHitFraction(BulletBody obj, float val);
513
514public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
515
516public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
517
518public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
519
520public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
521
522public abstract float GetCcdMotionThreshold(BulletBody obj);
523
524public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
525
526public abstract float GetCcdSweptSphereRadius(BulletBody obj);
527
528public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
529
530public abstract IntPtr GetUserPointer(BulletBody obj);
531
532public abstract void SetUserPointer(BulletBody obj, IntPtr val);
533
534// =====================================================================================
535// btRigidBody entries
536public abstract void ApplyGravity(BulletBody obj);
537
538public abstract void SetGravity(BulletBody obj, Vector3 val);
539
540public abstract Vector3 GetGravity(BulletBody obj);
541
542public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
543
544public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
545
546public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
547
548public abstract float GetLinearDamping(BulletBody obj);
549
550public abstract float GetAngularDamping(BulletBody obj);
551
552public abstract float GetLinearSleepingThreshold(BulletBody obj);
553
554public abstract void ApplyDamping(BulletBody obj, float timeStep);
555
556public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
557
558public abstract Vector3 GetLinearFactor(BulletBody obj);
559
560public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
561
562public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
563
564// Add a force to the object as if its mass is one.
565public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
566
567// Set the force being applied to the object as if its mass is one.
568public abstract void SetObjectForce(BulletBody obj, Vector3 force);
569
570public abstract Vector3 GetTotalForce(BulletBody obj);
571
572public abstract Vector3 GetTotalTorque(BulletBody obj);
573
574public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
575
576public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
577
578public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
579
580public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
581
582// Apply force at the given point. Will add torque to the object.
583public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
584
585// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
586public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
587
588// Apply impulse to the object's torque. Force is scaled by object's mass.
589public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
590
591// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
592public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
593
594public abstract void ClearForces(BulletBody obj);
595
596public abstract void ClearAllForces(BulletBody obj);
597
598public abstract void UpdateInertiaTensor(BulletBody obj);
599
600public abstract Vector3 GetLinearVelocity(BulletBody obj);
601
602public abstract Vector3 GetAngularVelocity(BulletBody obj);
603
604public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
605
606public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
607
608public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
609
610public abstract void Translate(BulletBody obj, Vector3 trans);
611
612public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
613
614public abstract bool WantsSleeping(BulletBody obj);
615
616public abstract void SetAngularFactor(BulletBody obj, float factor);
617
618public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
619
620public abstract Vector3 GetAngularFactor(BulletBody obj);
621
622public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
623
624public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
625
626public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
627
628public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
629
630public abstract int GetNumConstraintRefs(BulletBody obj);
631
632public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask);
633
634// =====================================================================================
635// btCollisionShape entries
636
637public abstract float GetAngularMotionDisc(BulletShape shape);
638
639public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
640
641public abstract bool IsPolyhedral(BulletShape shape);
642
643public abstract bool IsConvex2d(BulletShape shape);
644
645public abstract bool IsConvex(BulletShape shape);
646
647public abstract bool IsNonMoving(BulletShape shape);
648
649public abstract bool IsConcave(BulletShape shape);
650
651public abstract bool IsCompound(BulletShape shape);
652
653public abstract bool IsSoftBody(BulletShape shape);
654
655public abstract bool IsInfinite(BulletShape shape);
656
657public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
658
659public abstract Vector3 GetLocalScaling(BulletShape shape);
660
661public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
662
663public abstract int GetShapeType(BulletShape shape);
664
665public abstract void SetMargin(BulletShape shape, float val);
666
667public abstract float GetMargin(BulletShape shape);
668
669// =====================================================================================
670// Debugging
671public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
672
673public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
674
675public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
676
677public virtual void DumpActivationInfo(BulletWorld sim) { }
678
679public virtual void DumpAllInfo(BulletWorld sim) { }
680
681public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
682
683public virtual void ResetBroadphasePool(BulletWorld sim) { }
684
685public virtual void ResetConstraintSolver(BulletWorld sim) { }
686
687};
688}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..7603254 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -56,19 +56,19 @@ public sealed class BSCharacter : BSPhysObject
56 private int _physicsActorType; 56 private int _physicsActorType;
57 private bool _isPhysical; 57 private bool _isPhysical;
58 private bool _flying; 58 private bool _flying;
59 private bool _wasWalking; // 'true' if the avatar was walking/moving last frame
59 private bool _setAlwaysRun; 60 private bool _setAlwaysRun;
60 private bool _throttleUpdates; 61 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater; 62 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity; 63 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic; 64 private bool _kinematic;
66 private float _buoyancy; 65 private float _buoyancy;
67 66
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 67 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity). 68 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71 69
70 private BSVMotor _velocityMotor;
71
72 private OMV.Vector3 _PIDTarget; 72 private OMV.Vector3 _PIDTarget;
73 private bool _usePID; 73 private bool _usePID;
74 private float _PIDTau; 74 private float _PIDTau;
@@ -83,34 +83,37 @@ public sealed class BSCharacter : BSPhysObject
83 _physicsActorType = (int)ActorTypes.Agent; 83 _physicsActorType = (int)ActorTypes.Agent;
84 _position = pos; 84 _position = pos;
85 85
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; 86 _flying = isFlying;
87 _wasWalking = true; // causes first step to initialize standing
93 _orientation = OMV.Quaternion.Identity; 88 _orientation = OMV.Quaternion.Identity;
94 _velocity = OMV.Vector3.Zero; 89 _velocity = OMV.Vector3.Zero;
95 _appliedVelocity = OMV.Vector3.Zero;
96 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
97 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 91 _currentFriction = BSParam.AvatarStandingFriction;
98 _avatarDensity = PhysicsScene.Params.avatarDensity; 92 _avatarDensity = BSParam.AvatarDensity;
93
94 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
95 // replace with the default values.
96 _size = size;
97 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
98 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
99 99
100 // The dimensions of the avatar capsule are kept in the scale. 100 // The dimensions of the physical capsule are kept in the scale.
101 // Physics creates a unit capsule which is scaled by the physics engine. 101 // Physics creates a unit capsule which is scaled by the physics engine.
102 ComputeAvatarScale(_size); 102 Scale = ComputeAvatarScale(_size);
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 103 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 104 ComputeAvatarVolumeAndMass();
105
106 SetupMovementMotor();
107
105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 108 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 109 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
107 110
108 // do actual create at taint time 111 // do actual creation in taint time
109 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 112 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
110 { 113 {
111 DetailLog("{0},BSCharacter.create,taint", LocalID); 114 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape 115 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); 116 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
114 117
115 SetPhysicalProperties(); 118 SetPhysicalProperties();
116 }); 119 });
@@ -120,54 +123,198 @@ public sealed class BSCharacter : BSPhysObject
120 // called when this character is being destroyed and the resources should be released 123 // called when this character is being destroyed and the resources should be released
121 public override void Destroy() 124 public override void Destroy()
122 { 125 {
126 base.Destroy();
127
123 DetailLog("{0},BSCharacter.Destroy", LocalID); 128 DetailLog("{0},BSCharacter.Destroy", LocalID);
124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 129 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
125 { 130 {
126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 131 PhysicsScene.Shapes.DereferenceBody(PhysBody, true /* inTaintTime */, null /* bodyCallback */);
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 132 PhysBody.Clear();
133 PhysicsScene.Shapes.DereferenceShape(PhysShape, true /* inTaintTime */, null /* bodyCallback */);
134 PhysShape.Clear();
128 }); 135 });
129 } 136 }
130 137
131 private void SetPhysicalProperties() 138 private void SetPhysicalProperties()
132 { 139 {
133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 140 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
134 141
135 ZeroMotion(true); 142 ZeroMotion(true);
136 ForcePosition = _position; 143 ForcePosition = _position;
144
137 // Set the velocity and compute the proper friction 145 // Set the velocity and compute the proper friction
146 _velocityMotor.Reset();
147 _velocityMotor.SetTarget(_velocity);
148 _velocityMotor.SetCurrent(_velocity);
138 ForceVelocity = _velocity; 149 ForceVelocity = _velocity;
139 150
140 // This will enable or disable the flying buoyancy of the avatar. 151 // This will enable or disable the flying buoyancy of the avatar.
141 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 152 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying; 153 Flying = _flying;
143 154
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); 155 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); 156 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 157 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 158 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
148 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 159 if (BSParam.CcdMotionThreshold > 0f)
149 { 160 {
150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 161 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 162 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
152 } 163 }
153 164
154 UpdatePhysicalMassProperties(RawMass); 165 UpdatePhysicalMassProperties(RawMass, false);
155 166
156 // Make so capsule does not fall over 167 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); 168 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
158 169
159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 170 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
160 171
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 172 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
162 173
163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 174 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); 175 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 176 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
166 177
167 // Do this after the object has been added to the world 178 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, 179 PhysBody.collisionType = CollisionType.Avatar;
169 (uint)CollisionFilterGroups.AvatarFilter, 180 PhysBody.ApplyCollisionMask(PhysicsScene);
170 (uint)CollisionFilterGroups.AvatarMask); 181 }
182
183 // The avatar's movement is controlled by this motor that speeds up and slows down
184 // the avatar seeking to reach the motor's target speed.
185 // This motor runs as a prestep action for the avatar so it will keep the avatar
186 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
187 private void SetupMovementMotor()
188 {
189 // Infinite decay and timescale values so motor only changes current to target values.
190 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
191 0.2f, // time scale
192 BSMotor.Infinite, // decay time scale
193 BSMotor.InfiniteVector, // friction timescale
194 1f // efficiency
195 );
196 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
197
198 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
199 {
200 // TODO: Decide if the step parameters should be changed depending on the avatar's
201 // state (flying, colliding, ...). There is code in ODE to do this.
202
203 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
204 // specified for the avatar is the one that should be used. For falling, if the avatar
205 // is not flying and is not colliding then it is presumed to be falling and the Z
206 // component is not fooled with (thus allowing gravity to do its thing).
207 // When the avatar is standing, though, the user has specified a velocity of zero and
208 // the avatar should be standing. But if the avatar is pushed by something in the world
209 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
210 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
211 // errors can creap in and the avatar will slowly float off in some direction.
212 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
213 // from real pushing.OMV.Vector3.Zero;
214 // The code below keeps setting the velocity to zero hoping the world will keep pushing.
215
216 _velocityMotor.Step(timeStep);
217
218 // If we're not supposed to be moving, make sure things are zero.
219 if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero && IsColliding)
220 {
221 // The avatar shouldn't be moving
222 _velocityMotor.Zero();
223 ZeroMotion(true /* inTaintTime */);
224
225 // Standing has more friction on the ground
226 if (_currentFriction != BSParam.AvatarStandingFriction)
227 {
228 _currentFriction = BSParam.AvatarStandingFriction;
229 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
230 }
231 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1}", LocalID, _velocityMotor.TargetValue);
232
233 _wasWalking = false;
234 }
235 else
236 {
237 OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
238
239 if (_currentFriction != BSParam.AvatarFriction)
240 {
241 // Probably starting up walking. Set friction to moving friction.
242 _currentFriction = BSParam.AvatarFriction;
243 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
244 }
245
246 // If falling, we keep the world's downward vector no matter what the other axis specify.
247 if (!Flying && !IsColliding)
248 {
249 stepVelocity.Z = _velocity.Z;
250 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
251 }
252
253 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
254 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
255
256 // Should we check for move force being small and forcing velocity to zero?
257
258 // Add special movement force to allow avatars to walk up stepped surfaces.
259 moveForce += WalkUpStairs();
260
261 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
262 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
263 _wasWalking = true;
264 }
265 });
266 }
267
268 // Decide of the character is colliding with a low object and compute a force to pop the
269 // avatar up so it has a chance of walking up and over the low object.
270 private OMV.Vector3 WalkUpStairs()
271 {
272 OMV.Vector3 ret = OMV.Vector3.Zero;
273
274 // This test is done if moving forward, not flying and is colliding with something.
275 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
276 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
277 if (IsColliding && !Flying && TargetSpeed > 0.1f /* && ForwardSpeed < 0.1f */)
278 {
279 // The range near the character's feet where we will consider stairs
280 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
281 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
282
283 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is
284 foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
285 {
286 // Don't care about collisions with the terrain
287 if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
288 {
289 OMV.Vector3 touchPosition = kvp.Value.Position;
290 // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
291 // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
292 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
293 {
294 // This contact is within the 'near the feet' range.
295 // The normal should be our contact point to the object so it is pointing away
296 // thus the difference between our facing orientation and the normal should be small.
297 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
298 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
299 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
300 if (diff < BSParam.AvatarStepApproachFactor)
301 {
302 // Found the stairs contact point. Push up a little to raise the character.
303 float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
304 ret = new OMV.Vector3(0f, 0f, upForce);
305
306 // Also move the avatar up for the new height
307 OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
308 ForcePosition = RawPosition + displacement;
309 }
310 DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
311 LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
312 }
313 }
314 }
315 }
316
317 return ret;
171 } 318 }
172 319
173 public override void RequestPhysicsterseUpdate() 320 public override void RequestPhysicsterseUpdate()
@@ -185,24 +332,31 @@ public sealed class BSCharacter : BSPhysObject
185 } 332 }
186 333
187 set { 334 set {
188 // When an avatar's size is set, only the height is changed.
189 _size = value; 335 _size = value;
190 ComputeAvatarScale(_size); 336 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
337 // replace with the default values.
338 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
339 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
340
341 Scale = ComputeAvatarScale(_size);
191 ComputeAvatarVolumeAndMass(); 342 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 343 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 344 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
194 345
195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 346 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
196 { 347 {
197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 348 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
198 UpdatePhysicalMassProperties(RawMass); 349 {
350 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
351 UpdatePhysicalMassProperties(RawMass, true);
352 // Make sure this change appears as a property update event
353 PhysicsScene.PE.PushUpdate(PhysBody);
354 }
199 }); 355 });
200 356
201 } 357 }
202 } 358 }
203 359
204 public override OMV.Vector3 Scale { get; set; }
205
206 public override PrimitiveBaseShape Shape 360 public override PrimitiveBaseShape Shape
207 { 361 {
208 set { BaseShape = value; } 362 set { BaseShape = value; }
@@ -219,6 +373,10 @@ public sealed class BSCharacter : BSPhysObject
219 public override bool Selected { 373 public override bool Selected {
220 set { _selected = value; } 374 set { _selected = value; }
221 } 375 }
376 public override bool IsSelected
377 {
378 get { return _selected; }
379 }
222 public override void CrossingFailure() { return; } 380 public override void CrossingFailure() { return; }
223 public override void link(PhysicsActor obj) { return; } 381 public override void link(PhysicsActor obj) { return; }
224 public override void delink() { return; } 382 public override void delink() { return; }
@@ -236,7 +394,8 @@ public sealed class BSCharacter : BSPhysObject
236 // Zero some other properties directly into the physics engine 394 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 395 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 { 396 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 397 if (PhysBody.HasPhysicalBody)
398 PhysicsScene.PE.ClearAllForces(PhysBody);
240 }); 399 });
241 } 400 }
242 public override void ZeroAngularMotion(bool inTaintTime) 401 public override void ZeroAngularMotion(bool inTaintTime)
@@ -245,10 +404,13 @@ public sealed class BSCharacter : BSPhysObject
245 404
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 405 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 { 406 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 407 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 408 {
250 // The next also get rid of applied linear force but the linear velocity is untouched. 409 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
251 BulletSimAPI.ClearForces2(PhysBody.ptr); 410 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
411 // The next also get rid of applied linear force but the linear velocity is untouched.
412 PhysicsScene.PE.ClearForces(PhysBody);
413 }
252 }); 414 });
253 } 415 }
254 416
@@ -263,29 +425,31 @@ public sealed class BSCharacter : BSPhysObject
263 public override OMV.Vector3 Position { 425 public override OMV.Vector3 Position {
264 get { 426 get {
265 // Don't refetch the position because this function is called a zillion times 427 // Don't refetch the position because this function is called a zillion times
266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); 428 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
267 return _position; 429 return _position;
268 } 430 }
269 set { 431 set {
270 _position = value; 432 _position = value;
271 PositionSanityCheck();
272 433
273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 434 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
274 { 435 {
275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 436 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 437 ForcePosition = _position;
277 }); 438 });
278 } 439 }
279 } 440 }
280 public override OMV.Vector3 ForcePosition { 441 public override OMV.Vector3 ForcePosition {
281 get { 442 get {
282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 443 _position = PhysicsScene.PE.GetPosition(PhysBody);
283 return _position; 444 return _position;
284 } 445 }
285 set { 446 set {
286 _position = value; 447 _position = value;
287 PositionSanityCheck(); 448 if (PhysBody.HasPhysicalBody)
288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 449 {
450 PositionSanityCheck();
451 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
452 }
289 } 453 }
290 } 454 }
291 455
@@ -297,8 +461,17 @@ public sealed class BSCharacter : BSPhysObject
297 { 461 {
298 bool ret = false; 462 bool ret = false;
299 463
464 // TODO: check for out of bounds
465 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
466 {
467 // The character is out of the known/simulated area.
468 // Upper levels of code will handle the transition to other areas so, for
469 // the time, we just ignore the position.
470 return ret;
471 }
472
300 // If below the ground, move the avatar up 473 // If below the ground, move the avatar up
301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 474 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
302 if (Position.Z < terrainHeight) 475 if (Position.Z < terrainHeight)
303 { 476 {
304 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 477 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
@@ -307,7 +480,7 @@ public sealed class BSCharacter : BSPhysObject
307 } 480 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 481 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 482 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 483 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 484 if (Position.Z < waterHeight)
312 { 485 {
313 _position.Z = waterHeight; 486 _position.Z = waterHeight;
@@ -315,7 +488,6 @@ public sealed class BSCharacter : BSPhysObject
315 } 488 }
316 } 489 }
317 490
318 // TODO: check for out of bounds
319 return ret; 491 return ret;
320 } 492 }
321 493
@@ -332,7 +504,8 @@ public sealed class BSCharacter : BSPhysObject
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 504 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 { 505 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 506 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 507 if (PhysBody.HasPhysicalBody)
508 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
336 }); 509 });
337 ret = true; 510 ret = true;
338 } 511 }
@@ -345,10 +518,10 @@ public sealed class BSCharacter : BSPhysObject
345 public override float RawMass { 518 public override float RawMass {
346 get {return _mass; } 519 get {return _mass; }
347 } 520 }
348 public override void UpdatePhysicalMassProperties(float physMass) 521 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
349 { 522 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 523 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); 524 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
352 } 525 }
353 526
354 public override OMV.Vector3 Force { 527 public override OMV.Vector3 Force {
@@ -359,7 +532,8 @@ public sealed class BSCharacter : BSPhysObject
359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 532 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
360 { 533 {
361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 534 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 535 if (PhysBody.HasPhysicalBody)
536 PhysicsScene.PE.SetObjectForce(PhysBody, _force);
363 }); 537 });
364 } 538 }
365 } 539 }
@@ -376,6 +550,36 @@ public sealed class BSCharacter : BSPhysObject
376 550
377 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 551 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
378 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 552 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
553
554 // Sets the target in the motor. This starts the changing of the avatar's velocity.
555 public override OMV.Vector3 TargetVelocity
556 {
557 get
558 {
559 return _velocityMotor.TargetValue;
560 }
561 set
562 {
563 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
564 OMV.Vector3 targetVel = value;
565 if (_setAlwaysRun)
566 targetVel *= BSParam.AvatarAlwaysRunFactor;
567
568 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
569 {
570 _velocityMotor.Reset();
571 _velocityMotor.SetTarget(targetVel);
572 _velocityMotor.SetCurrent(_velocity);
573 _velocityMotor.Enabled = true;
574 });
575 }
576 }
577 public override OMV.Vector3 RawVelocity
578 {
579 get { return _velocity; }
580 set { _velocity = value; }
581 }
582 // Directly setting velocity means this is what the user really wants now.
379 public override OMV.Vector3 Velocity { 583 public override OMV.Vector3 Velocity {
380 get { return _velocity; } 584 get { return _velocity; }
381 set { 585 set {
@@ -383,6 +587,12 @@ public sealed class BSCharacter : BSPhysObject
383 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 587 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
384 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 588 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
385 { 589 {
590 _velocityMotor.Reset();
591 _velocityMotor.SetCurrent(_velocity);
592 _velocityMotor.SetTarget(_velocity);
593 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
594 _velocityMotor.Enabled = false;
595
386 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 596 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
387 ForceVelocity = _velocity; 597 ForceVelocity = _velocity;
388 }); 598 });
@@ -391,30 +601,11 @@ public sealed class BSCharacter : BSPhysObject
391 public override OMV.Vector3 ForceVelocity { 601 public override OMV.Vector3 ForceVelocity {
392 get { return _velocity; } 602 get { return _velocity; }
393 set { 603 set {
394 // Depending on whether the avatar is moving or not, change the friction 604 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 605
416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 606 _velocity = value;
417 BulletSimAPI.Activate2(PhysBody.ptr, true); 607 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
608 PhysicsScene.PE.Activate(PhysBody, true);
418 } 609 }
419 } 610 }
420 public override OMV.Vector3 Torque { 611 public override OMV.Vector3 Torque {
@@ -439,13 +630,16 @@ public sealed class BSCharacter : BSPhysObject
439 public override OMV.Quaternion Orientation { 630 public override OMV.Quaternion Orientation {
440 get { return _orientation; } 631 get { return _orientation; }
441 set { 632 set {
442 _orientation = value; 633 // 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); 634 // the viewer doesn't trust us.
444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 635 if (_orientation != value)
445 { 636 {
446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 637 _orientation = value;
447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 638 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
448 }); 639 {
640 ForceOrientation = _orientation;
641 });
642 }
449 } 643 }
450 } 644 }
451 // Go directly to Bullet to get/set the value. 645 // Go directly to Bullet to get/set the value.
@@ -453,13 +647,17 @@ public sealed class BSCharacter : BSPhysObject
453 { 647 {
454 get 648 get
455 { 649 {
456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 650 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
457 return _orientation; 651 return _orientation;
458 } 652 }
459 set 653 set
460 { 654 {
461 _orientation = value; 655 _orientation = value;
462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 656 if (PhysBody.HasPhysicalBody)
657 {
658 // _position = PhysicsScene.PE.GetPosition(BSBody);
659 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
660 }
463 } 661 }
464 } 662 }
465 public override int PhysicsActorType { 663 public override int PhysicsActorType {
@@ -478,10 +676,14 @@ public sealed class BSCharacter : BSPhysObject
478 public override bool IsStatic { 676 public override bool IsStatic {
479 get { return false; } 677 get { return false; }
480 } 678 }
679 public override bool IsPhysicallyActive {
680 get { return true; }
681 }
481 public override bool Flying { 682 public override bool Flying {
482 get { return _flying; } 683 get { return _flying; }
483 set { 684 set {
484 _flying = value; 685 _flying = value;
686
485 // simulate flying by changing the effect of gravity 687 // simulate flying by changing the effect of gravity
486 Buoyancy = ComputeBuoyancyFromFlying(_flying); 688 Buoyancy = ComputeBuoyancyFromFlying(_flying);
487 } 689 }
@@ -500,27 +702,18 @@ public sealed class BSCharacter : BSPhysObject
500 get { return _throttleUpdates; } 702 get { return _throttleUpdates; }
501 set { _throttleUpdates = value; } 703 set { _throttleUpdates = value; }
502 } 704 }
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 { 705 public override bool FloatOnWater {
516 set { 706 set {
517 _floatOnWater = value; 707 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 708 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 { 709 {
520 if (_floatOnWater) 710 if (PhysBody.HasPhysicalBody)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 711 {
522 else 712 if (_floatOnWater)
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 713 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
714 else
715 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
716 }
524 }); 717 });
525 } 718 }
526 } 719 }
@@ -549,11 +742,15 @@ public sealed class BSCharacter : BSPhysObject
549 } 742 }
550 public override float ForceBuoyancy { 743 public override float ForceBuoyancy {
551 get { return _buoyancy; } 744 get { return _buoyancy; }
552 set { _buoyancy = value; 745 set {
746 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
747
748 _buoyancy = value;
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 749 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object 750 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 751 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 752 if (PhysBody.HasPhysicalBody)
753 PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav));
557 } 754 }
558 } 755 }
559 756
@@ -589,24 +786,40 @@ public sealed class BSCharacter : BSPhysObject
589 public override float APIDStrength { set { return; } } 786 public override float APIDStrength { set { return; } }
590 public override float APIDDamping { set { return; } } 787 public override float APIDDamping { set { return; } }
591 788
592 public override void AddForce(OMV.Vector3 force, bool pushforce) { 789 public override void AddForce(OMV.Vector3 force, bool pushforce)
790 {
791 // Since this force is being applied in only one step, make this a force per second.
792 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
793 AddForce(addForce, pushforce, false);
794 }
795 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
593 if (force.IsFinite()) 796 if (force.IsFinite())
594 { 797 {
595 _force.X += force.X; 798 float magnitude = force.Length();
596 _force.Y += force.Y; 799 if (magnitude > BSParam.MaxAddForceMagnitude)
597 _force.Z += force.Z;
598 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
600 { 800 {
601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 801 // Force has a limit
602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 802 force = force / magnitude * BSParam.MaxAddForceMagnitude;
803 }
804
805 OMV.Vector3 addForce = force;
806 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
807
808 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
809 {
810 // Bullet adds this central force to the total force for this tick
811 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
812 if (PhysBody.HasPhysicalBody)
813 {
814 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
815 }
603 }); 816 });
604 } 817 }
605 else 818 else
606 { 819 {
607 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); 820 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
821 return;
608 } 822 }
609 //m_lastUpdateSent = false;
610 } 823 }
611 824
612 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 825 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@@ -614,24 +827,31 @@ public sealed class BSCharacter : BSPhysObject
614 public override void SetMomentum(OMV.Vector3 momentum) { 827 public override void SetMomentum(OMV.Vector3 momentum) {
615 } 828 }
616 829
617 private void ComputeAvatarScale(OMV.Vector3 size) 830 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
618 { 831 {
619 // The 'size' given by the simulator is the mid-point of the avatar 832 OMV.Vector3 newScale;
620 // and X and Y are unspecified. 833
621 834 // Bullet's capsule total height is the "passed height + radius * 2";
622 OMV.Vector3 newScale = size; 835 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 836 // The number we pass in for 'scaling' is the multiplier to get that base
624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 837 // shape to be the size desired.
625 838 // 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 839 // (size.Z) and remove the caps.
627 // The 1.15f came from ODE. Not sure what this factors in. 840 // Another oddity of the Bullet capsule implementation is that it presumes the Y
628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); 841 // dimension is the radius of the capsule. Even though some of the code allows
842 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
843
844 // Scale is multiplier of radius with one of "0.5"
845 newScale.X = size.X / 2f;
846 newScale.Y = size.Y / 2f;
629 847
630 // The total scale height is the central cylindar plus the caps on the two ends. 848 // 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); 849 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
850 // If smaller than the endcaps, just fake like we're almost that small
851 if (newScale.Z < 0)
852 newScale.Z = 0.1f;
632 853
633 // Convert diameters to radii and height to half height -- the way Bullet expects it. 854 return newScale;
634 Scale = newScale / 2f;
635 } 855 }
636 856
637 // set _avatarVolume and _mass based on capsule size, _density and Scale 857 // set _avatarVolume and _mass based on capsule size, _density and Scale
@@ -639,14 +859,14 @@ public sealed class BSCharacter : BSPhysObject
639 { 859 {
640 _avatarVolume = (float)( 860 _avatarVolume = (float)(
641 Math.PI 861 Math.PI
642 * Scale.X 862 * Size.X / 2f
643 * Scale.Y // the area of capsule cylinder 863 * Size.Y / 2f // the area of capsule cylinder
644 * Scale.Z // times height of capsule cylinder 864 * Size.Z // times height of capsule cylinder
645 + 1.33333333f 865 + 1.33333333f
646 * Math.PI 866 * Math.PI
647 * Scale.X 867 * Size.X / 2f
648 * Math.Min(Scale.X, Scale.Y) 868 * Math.Min(Size.X, Size.Y) / 2
649 * Scale.Y // plus the volume of the capsule end caps 869 * Size.Y / 2f // plus the volume of the capsule end caps
650 ); 870 );
651 _mass = _avatarDensity * _avatarVolume; 871 _mass = _avatarDensity * _avatarVolume;
652 } 872 }
@@ -657,27 +877,29 @@ public sealed class BSCharacter : BSPhysObject
657 { 877 {
658 _position = entprop.Position; 878 _position = entprop.Position;
659 _orientation = entprop.Rotation; 879 _orientation = entprop.Rotation;
660 _velocity = entprop.Velocity; 880
881 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
882 // and will send agent updates to the clients if velocity changes by more than
883 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
884 // extra updates.
885 if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f))
886 _velocity = entprop.Velocity;
887
661 _acceleration = entprop.Acceleration; 888 _acceleration = entprop.Acceleration;
662 _rotationalVelocity = entprop.RotationalVelocity; 889 _rotationalVelocity = entprop.RotationalVelocity;
890
663 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 891 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
664 PositionSanityCheck(true); 892 if (PositionSanityCheck(true))
893 {
894 entprop.Position = _position;
895 }
665 896
666 // remember the current and last set values 897 // remember the current and last set values
667 LastEntityProperties = CurrentEntityProperties; 898 LastEntityProperties = CurrentEntityProperties;
668 CurrentEntityProperties = entprop; 899 CurrentEntityProperties = entprop;
669 900
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 901 // Tell the linkset about value changes
680 Linkset.UpdateProperties(this); 902 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
681 903
682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 904 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
683 // base.RequestPhysicsterseUpdate(); 905 // base.RequestPhysicsterseUpdate();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 65fac00..b813974 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -36,7 +36,8 @@ public abstract class BSConstraint : IDisposable
36{ 36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]"; 37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38 38
39 protected BulletSim m_world; 39 protected BulletWorld m_world;
40 protected BSScene PhysicsScene;
40 protected BulletBody m_body1; 41 protected BulletBody m_body1;
41 protected BulletBody m_body2; 42 protected BulletBody m_body2;
42 protected BulletConstraint m_constraint; 43 protected BulletConstraint m_constraint;
@@ -48,8 +49,10 @@ public abstract class BSConstraint : IDisposable
48 public abstract ConstraintType Type { get; } 49 public abstract ConstraintType Type { get; }
49 public bool IsEnabled { get { return m_enabled; } } 50 public bool IsEnabled { get { return m_enabled; } }
50 51
51 public BSConstraint() 52 public BSConstraint(BulletWorld world)
52 { 53 {
54 m_world = world;
55 PhysicsScene = m_world.physicsScene;
53 } 56 }
54 57
55 public virtual void Dispose() 58 public virtual void Dispose()
@@ -57,15 +60,15 @@ public abstract class BSConstraint : IDisposable
57 if (m_enabled) 60 if (m_enabled)
58 { 61 {
59 m_enabled = false; 62 m_enabled = false;
60 if (m_constraint.ptr != IntPtr.Zero) 63 if (m_constraint.HasPhysicalConstraint)
61 { 64 {
62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
64 BSScene.DetailLogZero, 67 BSScene.DetailLogZero,
65 m_body1.ID, m_body1.ptr.ToString("X"), 68 m_body1.ID, m_body1.AddrString,
66 m_body2.ID, m_body2.ptr.ToString("X"), 69 m_body2.ID, m_body2.AddrString,
67 success); 70 success);
68 m_constraint.ptr = System.IntPtr.Zero; 71 m_constraint.Clear();
69 } 72 }
70 } 73 }
71 } 74 }
@@ -74,7 +77,7 @@ public abstract class BSConstraint : IDisposable
74 { 77 {
75 bool ret = false; 78 bool ret = false;
76 if (m_enabled) 79 if (m_enabled)
77 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high); 80 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
78 return ret; 81 return ret;
79 } 82 }
80 83
@@ -82,7 +85,7 @@ public abstract class BSConstraint : IDisposable
82 { 85 {
83 bool ret = false; 86 bool ret = false;
84 if (m_enabled) 87 if (m_enabled)
85 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high); 88 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
86 return ret; 89 return ret;
87 } 90 }
88 91
@@ -91,7 +94,7 @@ public abstract class BSConstraint : IDisposable
91 bool ret = false; 94 bool ret = false;
92 if (m_enabled) 95 if (m_enabled)
93 { 96 {
94 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt); 97 PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt);
95 ret = true; 98 ret = true;
96 } 99 }
97 return ret; 100 return ret;
@@ -103,7 +106,7 @@ public abstract class BSConstraint : IDisposable
103 if (m_enabled) 106 if (m_enabled)
104 { 107 {
105 // Recompute the internal transforms 108 // Recompute the internal transforms
106 BulletSimAPI.CalculateTransforms2(m_constraint.ptr); 109 PhysicsScene.PE.CalculateTransforms(m_constraint);
107 ret = true; 110 ret = true;
108 } 111 }
109 return ret; 112 return ret;
@@ -122,7 +125,7 @@ public abstract class BSConstraint : IDisposable
122 // Setting an object's mass to zero (making it static like when it's selected) 125 // Setting an object's mass to zero (making it static like when it's selected)
123 // automatically disables the constraints. 126 // automatically disables the constraints.
124 // If the link is enabled, be sure to set the constraint itself to enabled. 127 // If the link is enabled, be sure to set the constraint itself to enabled.
125 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true)); 128 PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true));
126 } 129 }
127 else 130 else
128 { 131 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 23ef052..ecb1b32 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -39,51 +39,49 @@ public sealed class BSConstraint6Dof : BSConstraint
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40 40
41 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
42 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
44 Vector3 frame2, Quaternion frame2rot, 44 Vector3 frame2, Quaternion frame2rot,
45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
46 : base(world)
46 { 47 {
47 m_world = world;
48 m_body1 = obj1; 48 m_body1 = obj1;
49 m_body2 = obj2; 49 m_body2 = obj2;
50 m_constraint = new BulletConstraint( 50 m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2,
51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
52 frame1, frame1rot, 51 frame1, frame1rot,
53 frame2, frame2rot, 52 frame2, frame2rot,
54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 53 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
55 m_enabled = true; 54 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 55 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID, 56 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 57 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
59 } 58 }
60 59
61 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, 60 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint, 61 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 62 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
63 : base(world)
64 { 64 {
65 m_world = world;
66 m_body1 = obj1; 65 m_body1 = obj1;
67 m_body2 = obj2; 66 m_body2 = obj2;
68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) 67 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 { 68 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 69 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID, 70 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 71 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 72 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 73 LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
75 m_enabled = false; 74 m_enabled = false;
76 } 75 }
77 else 76 else
78 { 77 {
79 m_constraint = new BulletConstraint( 78 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
80 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
81 joinPoint, 79 joinPoint,
82 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 80 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 81 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
84 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), 82 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString,
85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 83 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
86 if (m_constraint.ptr == IntPtr.Zero) 84 if (!m_constraint.HasPhysicalConstraint)
87 { 85 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 86 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID); 87 LogHeader, obj1.ID, obj2.ID);
@@ -101,7 +99,7 @@ public sealed class BSConstraint6Dof : BSConstraint
101 bool ret = false; 99 bool ret = false;
102 if (m_enabled) 100 if (m_enabled)
103 { 101 {
104 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); 102 PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
105 ret = true; 103 ret = true;
106 } 104 }
107 return ret; 105 return ret;
@@ -112,9 +110,9 @@ public sealed class BSConstraint6Dof : BSConstraint
112 bool ret = false; 110 bool ret = false;
113 if (m_enabled) 111 if (m_enabled)
114 { 112 {
115 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 113 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); 114 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 115 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
118 ret = true; 116 ret = true;
119 } 117 }
120 return ret; 118 return ret;
@@ -125,7 +123,7 @@ public sealed class BSConstraint6Dof : BSConstraint
125 bool ret = false; 123 bool ret = false;
126 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 124 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
127 if (m_enabled) 125 if (m_enabled)
128 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); 126 ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
129 return ret; 127 return ret;
130 } 128 }
131 129
@@ -135,7 +133,7 @@ public sealed class BSConstraint6Dof : BSConstraint
135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 133 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
136 if (m_enabled) 134 if (m_enabled)
137 { 135 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); 136 ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", 137 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); 138 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 } 139 }
@@ -146,7 +144,7 @@ public sealed class BSConstraint6Dof : BSConstraint
146 { 144 {
147 bool ret = false; 145 bool ret = false;
148 if (m_enabled) 146 if (m_enabled)
149 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); 147 ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
150 return ret; 148 return ret;
151 } 149 }
152} 150}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
index a9fd826..2aeff25 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -41,9 +41,9 @@ public sealed class BSConstraintCollection : IDisposable
41 delegate bool ConstraintAction(BSConstraint constrain); 41 delegate bool ConstraintAction(BSConstraint constrain);
42 42
43 private List<BSConstraint> m_constraints; 43 private List<BSConstraint> m_constraints;
44 private BulletSim m_world; 44 private BulletWorld m_world;
45 45
46 public BSConstraintCollection(BulletSim world) 46 public BSConstraintCollection(BulletWorld world)
47 { 47 {
48 m_world = world; 48 m_world = world;
49 m_constraints = new List<BSConstraint>(); 49 m_constraints = new List<BSConstraint>();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index ed3ffa7..7714a03 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -36,19 +36,17 @@ public sealed class BSConstraintHinge : BSConstraint
36{ 36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 38
39 public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2, 39 public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB, 40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB, 41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
43 { 44 {
44 m_world = world;
45 m_body1 = obj1; 45 m_body1 = obj1;
46 m_body2 = obj2; 46 m_body2 = obj2;
47 m_constraint = new BulletConstraint( 47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, 48 pivotInA, pivotInB, axisInA, axisInB,
49 pivotInA, pivotInB, 49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 axisInA, axisInB,
51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 m_enabled = true; 50 m_enabled = true;
53 } 51 }
54 52
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index dbc9039..fe7891e 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,32 +104,61 @@ 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 private bool enableAngularVerticalAttraction;
129 private bool enableAngularDeflection;
130 private 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 = false;
147 if (BSParam.VehicleDebuggingEnabled != ConfigurationParameters.numericFalse)
148 {
149 enableAngularVerticalAttraction = false;
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
161 #region Vehicle parameter setting
143 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 162 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
144 { 163 {
145 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 164 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
@@ -152,13 +171,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 171 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
153 break; 172 break;
154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 173 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 174 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
175 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
156 break; 176 break;
157 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 177 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
158 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 178 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
179 m_angularMotor.TimeScale = m_angularMotorTimescale;
159 break; 180 break;
160 case Vehicle.BANKING_EFFICIENCY: 181 case Vehicle.BANKING_EFFICIENCY:
161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 182 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
162 break; 183 break;
163 case Vehicle.BANKING_MIX: 184 case Vehicle.BANKING_MIX:
164 m_bankingMix = Math.Max(pValue, 0.01f); 185 m_bankingMix = Math.Max(pValue, 0.01f);
@@ -167,10 +188,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
167 m_bankingTimescale = Math.Max(pValue, 0.01f); 188 m_bankingTimescale = Math.Max(pValue, 0.01f);
168 break; 189 break;
169 case Vehicle.BUOYANCY: 190 case Vehicle.BUOYANCY:
170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 191 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
192 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy);
171 break; 193 break;
172 case Vehicle.HOVER_EFFICIENCY: 194 case Vehicle.HOVER_EFFICIENCY:
173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 195 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
174 break; 196 break;
175 case Vehicle.HOVER_HEIGHT: 197 case Vehicle.HOVER_HEIGHT:
176 m_VhoverHeight = pValue; 198 m_VhoverHeight = pValue;
@@ -185,33 +207,41 @@ namespace OpenSim.Region.Physics.BulletSPlugin
185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 207 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
186 break; 208 break;
187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 209 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 210 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
211 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 212 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 213 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 214 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
215 m_linearMotor.TimeScale = m_linearMotorTimescale;
192 break; 216 break;
193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 217 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 218 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
219 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
195 break; 220 break;
196 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 221 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
197 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 222 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
223 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
198 break; 224 break;
199 225
200 // These are vector properties but the engine lets you use a single float value to 226 // 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 227 // set all of the components to the same value
202 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 228 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
203 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 229 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
230 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
204 break; 231 break;
205 case Vehicle.ANGULAR_MOTOR_DIRECTION: 232 case Vehicle.ANGULAR_MOTOR_DIRECTION:
206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 233 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
207 // m_angularMotorApply = 100; 234 m_angularMotor.Zero();
235 m_angularMotor.SetTarget(m_angularMotorDirection);
208 break; 236 break;
209 case Vehicle.LINEAR_FRICTION_TIMESCALE: 237 case Vehicle.LINEAR_FRICTION_TIMESCALE:
210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 238 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
239 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
211 break; 240 break;
212 case Vehicle.LINEAR_MOTOR_DIRECTION: 241 case Vehicle.LINEAR_MOTOR_DIRECTION:
213 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 242 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 243 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
244 m_linearMotor.SetTarget(m_linearMotorDirection);
215 break; 245 break;
216 case Vehicle.LINEAR_MOTOR_OFFSET: 246 case Vehicle.LINEAR_MOTOR_OFFSET:
217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 247 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,21 +257,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
227 { 257 {
228 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 258 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 259 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
230 break; 261 break;
231 case Vehicle.ANGULAR_MOTOR_DIRECTION: 262 case Vehicle.ANGULAR_MOTOR_DIRECTION:
232 // Limit requested angular speed to 2 rps= 4 pi rads/sec 263 // Limit requested angular speed to 2 rps= 4 pi rads/sec
233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); 264 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 265 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 266 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 267 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
237 // m_angularMotorApply = 100; 268 m_angularMotor.Zero();
269 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break; 270 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE: 271 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 272 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
273 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
241 break; 274 break;
242 case Vehicle.LINEAR_MOTOR_DIRECTION: 275 case Vehicle.LINEAR_MOTOR_DIRECTION:
243 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 276 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 277 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
278 m_linearMotor.SetTarget(m_linearMotorDirection);
245 break; 279 break;
246 case Vehicle.LINEAR_MOTOR_OFFSET: 280 case Vehicle.LINEAR_MOTOR_OFFSET:
247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 281 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -303,7 +337,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
303 m_VhoverEfficiency = 0; 337 m_VhoverEfficiency = 0;
304 m_VhoverTimescale = 0; 338 m_VhoverTimescale = 0;
305 m_VehicleBuoyancy = 0; 339 m_VehicleBuoyancy = 0;
306 340
307 m_linearDeflectionEfficiency = 1; 341 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1; 342 m_linearDeflectionTimescale = 1;
309 343
@@ -319,6 +353,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
319 353
320 m_referenceFrame = Quaternion.Identity; 354 m_referenceFrame = Quaternion.Identity;
321 m_flags = (VehicleFlag)0; 355 m_flags = (VehicleFlag)0;
356
322 break; 357 break;
323 358
324 case Vehicle.TYPE_SLED: 359 case Vehicle.TYPE_SLED:
@@ -351,10 +386,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
351 m_bankingMix = 1; 386 m_bankingMix = 1;
352 387
353 m_referenceFrame = Quaternion.Identity; 388 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 389 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
355 m_flags &= 390 | VehicleFlag.HOVER_TERRAIN_ONLY
356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 391 | VehicleFlag.HOVER_GLOBAL_HEIGHT
357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 392 | VehicleFlag.HOVER_UP_ONLY);
393 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
394 | VehicleFlag.LIMIT_ROLL_ONLY
395 | VehicleFlag.LIMIT_MOTOR_UP);
396
358 break; 397 break;
359 case Vehicle.TYPE_CAR: 398 case Vehicle.TYPE_CAR:
360 m_linearMotorDirection = Vector3.Zero; 399 m_linearMotorDirection = Vector3.Zero;
@@ -498,6 +537,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
498 m_bankingEfficiency = 0; 537 m_bankingEfficiency = 0;
499 m_bankingMix = 0.7f; 538 m_bankingMix = 0.7f;
500 m_bankingTimescale = 5; 539 m_bankingTimescale = 5;
540
501 m_referenceFrame = Quaternion.Identity; 541 m_referenceFrame = Quaternion.Identity;
502 542
503 m_referenceFrame = Quaternion.Identity; 543 m_referenceFrame = Quaternion.Identity;
@@ -510,7 +550,30 @@ namespace OpenSim.Region.Physics.BulletSPlugin
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 550 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
511 break; 551 break;
512 } 552 }
553
554 // Update any physical parameters based on this type.
555 Refresh();
556
557 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
558 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
559 1f);
560 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
561
562 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
563 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
564 1f);
565 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
566
567 /* Not implemented
568 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
569 BSMotor.Infinite, BSMotor.InfiniteVector,
570 m_verticalAttractionEfficiency);
571 // Z goes away and we keep X and Y
572 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
573 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
574 */
513 } 575 }
576 #endregion // Vehicle parameter setting
514 577
515 // Some of the properties of this prim may have changed. 578 // Some of the properties of this prim may have changed.
516 // Do any updating needed for a vehicle 579 // Do any updating needed for a vehicle
@@ -518,13 +581,38 @@ namespace OpenSim.Region.Physics.BulletSPlugin
518 { 581 {
519 if (IsActive) 582 if (IsActive)
520 { 583 {
521 // Friction effects are handled by this vehicle code 584 // Remember the mass so we don't have to fetch it every step
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); 585 m_vehicleMass = Prim.Linkset.LinksetMass;
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); 586
524 587 // Friction affects are handled by this vehicle code
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); 588 float friction = 0f;
526 589 PhysicsScene.PE.SetFriction(Prim.PhysBody, friction);
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); 590
591 // Moderate angular movement introduced by Bullet.
592 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
593 // Maybe compute linear and angular factor and damping from params.
594 float angularDamping = BSParam.VehicleAngularDamping;
595 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping);
596
597 // Vehicles report collision events so we know when it's on the ground
598 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
599
600 Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass);
601 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia);
602 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody);
603
604 // Set the gravity for the vehicle depending on the buoyancy
605 // TODO: what should be done if prim and vehicle buoyancy differ?
606 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy);
607 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
608 PhysicsScene.PE.SetGravity(Prim.PhysBody, Vector3.Zero);
609
610 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4},grav={5}",
611 Prim.LocalID, m_vehicleMass, friction, Prim.Inertia, angularDamping, m_VehicleGravity);
612 }
613 else
614 {
615 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
528 } 616 }
529 } 617 }
530 618
@@ -546,116 +634,371 @@ namespace OpenSim.Region.Physics.BulletSPlugin
546 Refresh(); 634 Refresh();
547 } 635 }
548 636
637 #region Known vehicle value functions
638 // Vehicle physical parameters that we buffer from constant getting and setting.
639 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
640 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
641 // This does two things: 1) saves continuious calls into unmanaged code, and
642 // 2) signals when a physics property update must happen back to the simulator
643 // to update values modified for the vehicle.
644 private int m_knownChanged;
645 private int m_knownHas;
646 private float m_knownTerrainHeight;
647 private float m_knownWaterLevel;
648 private Vector3 m_knownPosition;
649 private Vector3 m_knownVelocity;
650 private Vector3 m_knownForce;
651 private Vector3 m_knownForceImpulse;
652 private Quaternion m_knownOrientation;
653 private Vector3 m_knownRotationalVelocity;
654 private Vector3 m_knownRotationalForce;
655 private Vector3 m_knownRotationalImpulse;
656 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
657
658 private const int m_knownChangedPosition = 1 << 0;
659 private const int m_knownChangedVelocity = 1 << 1;
660 private const int m_knownChangedForce = 1 << 2;
661 private const int m_knownChangedForceImpulse = 1 << 3;
662 private const int m_knownChangedOrientation = 1 << 4;
663 private const int m_knownChangedRotationalVelocity = 1 << 5;
664 private const int m_knownChangedRotationalForce = 1 << 6;
665 private const int m_knownChangedRotationalImpulse = 1 << 7;
666 private const int m_knownChangedTerrainHeight = 1 << 8;
667 private const int m_knownChangedWaterLevel = 1 << 9;
668 private const int m_knownChangedForwardVelocity = 1 <<10;
669
670 private void ForgetKnownVehicleProperties()
671 {
672 m_knownHas = 0;
673 m_knownChanged = 0;
674 }
675 // Push all the changed values back into the physics engine
676 private void PushKnownChanged()
677 {
678 if (m_knownChanged != 0)
679 {
680 if ((m_knownChanged & m_knownChangedPosition) != 0)
681 Prim.ForcePosition = m_knownPosition;
682
683 if ((m_knownChanged & m_knownChangedOrientation) != 0)
684 Prim.ForceOrientation = m_knownOrientation;
685
686 if ((m_knownChanged & m_knownChangedVelocity) != 0)
687 {
688 Prim.ForceVelocity = m_knownVelocity;
689 // Fake out Bullet by making it think the velocity is the same as last time.
690 // Bullet does a bunch of smoothing for changing parameters.
691 // Since the vehicle is demanding this setting, we override Bullet's smoothing
692 // by telling Bullet the value was the same last time.
693 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
694 }
695
696 if ((m_knownChanged & m_knownChangedForce) != 0)
697 Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
698
699 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
700 Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
701
702 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
703 {
704 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
705 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
706 }
707
708 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
709 Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
710
711 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
712 {
713 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
714 }
715
716 // If we set one of the values (ie, the physics engine didn't do it) we must force
717 // an UpdateProperties event to send the changes up to the simulator.
718 PhysicsScene.PE.PushUpdate(Prim.PhysBody);
719 }
720 m_knownChanged = 0;
721 }
722
723 // Since the computation of terrain height can be a little involved, this routine
724 // is used to fetch the height only once for each vehicle simulation step.
725 Vector3 lastRememberedHeightPos;
726 private float GetTerrainHeight(Vector3 pos)
727 {
728 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
729 {
730 lastRememberedHeightPos = pos;
731 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
732 m_knownHas |= m_knownChangedTerrainHeight;
733 }
734 return m_knownTerrainHeight;
735 }
736
737 // Since the computation of water level can be a little involved, this routine
738 // is used ot fetch the level only once for each vehicle simulation step.
739 private float GetWaterLevel(Vector3 pos)
740 {
741 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
742 {
743 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
744 m_knownHas |= m_knownChangedWaterLevel;
745 }
746 return (float)m_knownWaterLevel;
747 }
748
749 private Vector3 VehiclePosition
750 {
751 get
752 {
753 if ((m_knownHas & m_knownChangedPosition) == 0)
754 {
755 m_knownPosition = Prim.ForcePosition;
756 m_knownHas |= m_knownChangedPosition;
757 }
758 return m_knownPosition;
759 }
760 set
761 {
762 m_knownPosition = value;
763 m_knownChanged |= m_knownChangedPosition;
764 m_knownHas |= m_knownChangedPosition;
765 }
766 }
767
768 private Quaternion VehicleOrientation
769 {
770 get
771 {
772 if ((m_knownHas & m_knownChangedOrientation) == 0)
773 {
774 m_knownOrientation = Prim.ForceOrientation;
775 m_knownHas |= m_knownChangedOrientation;
776 }
777 return m_knownOrientation;
778 }
779 set
780 {
781 m_knownOrientation = value;
782 m_knownChanged |= m_knownChangedOrientation;
783 m_knownHas |= m_knownChangedOrientation;
784 }
785 }
786
787 private Vector3 VehicleVelocity
788 {
789 get
790 {
791 if ((m_knownHas & m_knownChangedVelocity) == 0)
792 {
793 m_knownVelocity = Prim.ForceVelocity;
794 m_knownHas |= m_knownChangedVelocity;
795 }
796 return (Vector3)m_knownVelocity;
797 }
798 set
799 {
800 m_knownVelocity = value;
801 m_knownChanged |= m_knownChangedVelocity;
802 m_knownHas |= m_knownChangedVelocity;
803 }
804 }
805
806 private void VehicleAddForce(Vector3 pForce)
807 {
808 if ((m_knownHas & m_knownChangedForce) == 0)
809 {
810 m_knownForce = Vector3.Zero;
811 m_knownHas |= m_knownChangedForce;
812 }
813 m_knownForce += pForce;
814 m_knownChanged |= m_knownChangedForce;
815 }
816
817 private void VehicleAddForceImpulse(Vector3 pImpulse)
818 {
819 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
820 {
821 m_knownForceImpulse = Vector3.Zero;
822 m_knownHas |= m_knownChangedForceImpulse;
823 }
824 m_knownForceImpulse += pImpulse;
825 m_knownChanged |= m_knownChangedForceImpulse;
826 }
827
828 private Vector3 VehicleRotationalVelocity
829 {
830 get
831 {
832 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
833 {
834 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
835 m_knownHas |= m_knownChangedRotationalVelocity;
836 }
837 return (Vector3)m_knownRotationalVelocity;
838 }
839 set
840 {
841 m_knownRotationalVelocity = value;
842 m_knownChanged |= m_knownChangedRotationalVelocity;
843 m_knownHas |= m_knownChangedRotationalVelocity;
844 }
845 }
846 private void VehicleAddAngularForce(Vector3 aForce)
847 {
848 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
849 {
850 m_knownRotationalForce = Vector3.Zero;
851 }
852 m_knownRotationalForce += aForce;
853 m_knownChanged |= m_knownChangedRotationalForce;
854 m_knownHas |= m_knownChangedRotationalForce;
855 }
856 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
857 {
858 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
859 {
860 m_knownRotationalImpulse = Vector3.Zero;
861 m_knownHas |= m_knownChangedRotationalImpulse;
862 }
863 m_knownRotationalImpulse += pImpulse;
864 m_knownChanged |= m_knownChangedRotationalImpulse;
865 }
866
867 // Vehicle relative forward velocity
868 private Vector3 VehicleForwardVelocity
869 {
870 get
871 {
872 if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
873 {
874 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
875 m_knownHas |= m_knownChangedForwardVelocity;
876 }
877 return m_knownForwardVelocity;
878 }
879 }
880 private float VehicleForwardSpeed
881 {
882 get
883 {
884 return VehicleForwardVelocity.X;
885 }
886 }
887
888 #endregion // Known vehicle value functions
889
549 // One step of the vehicle properties for the next 'pTimestep' seconds. 890 // One step of the vehicle properties for the next 'pTimestep' seconds.
550 internal void Step(float pTimestep) 891 internal void Step(float pTimestep)
551 { 892 {
552 if (!IsActive) return; 893 if (!IsActive) return;
553 894
554 // DEBUG 895 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
555 // Because Bullet does apply forces to the vehicle, our last computed 896 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562 897
563 m_vehicleMass = Prim.Linkset.LinksetMass; 898 ForgetKnownVehicleProperties();
564 899
565 MoveLinear(pTimestep); 900 MoveLinear(pTimestep);
566 // Commented out for debug
567 MoveAngular(pTimestep); 901 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570 902
571 LimitRotation(pTimestep); 903 LimitRotation(pTimestep);
572 904
573 // remember the position so next step we can limit absolute movement effects 905 // remember the position so next step we can limit absolute movement effects
574 m_lastPositionVector = Prim.ForcePosition; 906 m_lastPositionVector = VehiclePosition;
575 907
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG 908 // If we forced the changing of some vehicle parameters, update the values and
577 Prim.LocalID, 909 // for the physics engine to note the changes so an UpdateProperties event will happen.
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), 910 PushKnownChanged();
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), 911
580 Prim.Inertia, 912 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
581 m_vehicleMass 913 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
582 ); 914
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 915 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 916 Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
585 }// end Step 917 }
586 918
587 // Apply the effect of the linear motor. 919 // Apply the effect of the linear motor and other linear motions (like hover and float).
588 // Also does hover and float.
589 private void MoveLinear(float pTimestep) 920 private void MoveLinear(float pTimestep)
590 { 921 {
591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates 922 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 923
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete 924 ComputeLinearTerrainHeightCorrection(pTimestep);
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
602 m_lastLinearVelocityVector += addAmount;
603 925
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; 926 ComputeLinearHover(pTimestep);
605 m_linearMotorDirection *= (1f - decayFactor);
606 927
607 // Rotate new object velocity from vehicle relative to world coordinates 928 ComputeLinearBlockingEndPoint(pTimestep);
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
609 929
610 // Apply friction for next time 930 ComputeLinearMotorUp(pTimestep);
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
613 931
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", 932 ApplyGravity(pTimestep);
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, 933
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); 934 // If not changing some axis, reduce out velocity
617 } 935 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
618 else
619 { 936 {
620 // if what remains of direction is very small, zero it. 937 Vector3 vel = VehicleVelocity;
621 m_linearMotorDirection = Vector3.Zero; 938 if ((m_flags & (VehicleFlag.NO_X)) != 0)
622 m_lastLinearVelocityVector = Vector3.Zero; 939 vel.X = 0;
623 m_newVelocity = Vector3.Zero; 940 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
941 vel.Y = 0;
942 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
943 vel.Z = 0;
944 VehicleVelocity = vel;
945 }
624 946
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 947 // ==================================================================
948 // Clamp high or low velocities
949 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
950 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocity)
951 {
952 VehicleVelocity /= VehicleVelocity.Length();
953 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
626 } 954 }
955 else if (newVelocityLengthSq < 0.001f)
956 VehicleVelocity = Vector3.Zero;
627 957
628 // m_newVelocity is velocity computed from linear motor in world coordinates 958 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity );
629 959
630 // Gravity and Buoyancy 960 } // 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 961
635 /* 962 public void ComputeLinearVelocity(float pTimestep)
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... 963 {
637 // Preserve the current Z velocity 964 // Step the motor from the current value. Get the correction needed this step.
638 Vector3 vel_now = m_prim.Velocity; 965 Vector3 currentVel = VehicleVelocity * Quaternion.Inverse(VehicleOrientation);
639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 966 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVel);
640 */ 967
968 // Motor is vehicle coordinates. Rotate it to world coordinates
969 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation;
641 970
642 Vector3 pos = Prim.ForcePosition; 971 // If we're a ground vehicle, don't add any upward Z movement
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); 972 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
973 {
974 if (linearMotorVelocityW.Z > 0f)
975 linearMotorVelocityW.Z = 0f;
976 }
644 977
978 // Add this correction to the velocity to make it faster/slower.
979 VehicleVelocity += linearMotorVelocityW;
980
981 VDetailLog("{0}, MoveLinear,velocity,vehVel={1},correction={2},force={3}",
982 Prim.LocalID, VehicleVelocity, linearMotorCorrectionV, linearMotorVelocityW);
983 }
984
985 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
986 {
645 // If below the terrain, move us above the ground a little. 987 // If below the terrain, move us above the ground a little.
646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 988 // 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. 989 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 { 990 {
653 pos.Z = terrainHeight + 2; 991 // Force position because applying force won't get the vehicle through the terrain
654 Prim.ForcePosition = pos; 992 Vector3 newPosition = VehiclePosition;
655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 993 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
994 VehiclePosition = newPosition;
995 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
996 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
656 } 997 }
998 }
657 999
658 // Check if hovering 1000 public void ComputeLinearHover(float pTimestep)
1001 {
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 1002 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height 1003 // m_VhoverTimescale: time to achieve height
661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 1004 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -663,11 +1006,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
663 // We should hover, get the target height 1006 // We should hover, get the target height
664 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 1007 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
665 { 1008 {
666 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 1009 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
667 } 1010 }
668 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 1011 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
669 { 1012 {
670 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; 1013 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
671 } 1014 }
672 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 1015 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
673 { 1016 {
@@ -677,45 +1020,63 @@ namespace OpenSim.Region.Physics.BulletSPlugin
677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 1020 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
678 { 1021 {
679 // If body is already heigher, use its height as target height 1022 // If body is already heigher, use its height as target height
680 if (pos.Z > m_VhoverTargetHeight) 1023 if (VehiclePosition.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z; 1024 m_VhoverTargetHeight = VehiclePosition.Z;
682 } 1025 }
1026
683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1027 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
684 { 1028 {
685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 1029 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
686 { 1030 {
1031 Vector3 pos = VehiclePosition;
687 pos.Z = m_VhoverTargetHeight; 1032 pos.Z = m_VhoverTargetHeight;
688 Prim.ForcePosition = pos; 1033 VehiclePosition = pos;
1034
1035 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos);
689 } 1036 }
690 } 1037 }
691 else 1038 else
692 { 1039 {
693 float verticalError = pos.Z - m_VhoverTargetHeight; 1040 // Error is positive if below the target and negative if above.
694 // RA: where does the 50 come from? 1041 Vector3 hpos = VehiclePosition;
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 1042 float verticalError = m_VhoverTargetHeight - hpos.Z;
696 // Replace Vertical speed with correction figure if significant 1043 float verticalCorrection = verticalError / m_VhoverTimescale;
697 if (Math.Abs(verticalError) > 0.01f) 1044 verticalCorrection *= m_VhoverEfficiency;
698 { 1045
699 m_newVelocity.Z += verticalCorrectionVelocity; 1046 hpos.Z += verticalCorrection;
700 //KF: m_VhoverEfficiency is not yet implemented 1047 VehiclePosition = hpos;
701 } 1048
702 else if (verticalError < -0.01) 1049 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
703 { 1050 Vector3 vel = VehicleVelocity;
704 m_newVelocity.Z -= verticalCorrectionVelocity; 1051 vel.Z = 0f;
705 } 1052 VehicleVelocity = vel;
706 else 1053
707 { 1054 /*
708 m_newVelocity.Z = 0f; 1055 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
709 } 1056 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1057 verticalCorrection *= m_vehicleMass;
1058
1059 // TODO: implement m_VhoverEfficiency correctly
1060 VehicleAddForceImpulse(verticalCorrection);
1061 */
1062
1063 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
1064 Prim.LocalID, VehiclePosition, m_VhoverEfficiency,
1065 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1066 verticalError, verticalCorrection);
710 } 1067 }
711 1068
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
713 } 1069 }
1070 }
1071
1072 public bool ComputeLinearBlockingEndPoint(float pTimestep)
1073 {
1074 bool changed = false;
714 1075
1076 Vector3 pos = VehiclePosition;
715 Vector3 posChange = pos - m_lastPositionVector; 1077 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 1078 if (m_BlockingEndPoint != Vector3.Zero)
717 { 1079 {
718 bool changed = false;
719 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 1080 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
720 { 1081 {
721 pos.X -= posChange.X + 1; 1082 pos.X -= posChange.X + 1;
@@ -743,233 +1104,115 @@ namespace OpenSim.Region.Physics.BulletSPlugin
743 } 1104 }
744 if (changed) 1105 if (changed)
745 { 1106 {
746 Prim.ForcePosition = pos; 1107 VehiclePosition = pos;
747 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1108 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1109 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
749 } 1110 }
750 } 1111 }
1112 return changed;
1113 }
751 1114
752 #region downForce 1115 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
753 Vector3 downForce = Vector3.Zero; 1116 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
754 1117 // used with conjunction with banking: the strength of the banking will decay when the
1118 // vehicle no longer experiences collisions. The decay timescale is the same as
1119 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1120 // when they are in mid jump.
1121 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1122 // This is just using the ground and a general collision check. Should really be using
1123 // a downward raycast to find what is below.
1124 public void ComputeLinearMotorUp(float pTimestep)
1125 {
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1126 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 1127 {
757 // If the vehicle is motoring into the sky, get it going back down. 1128 // 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?? 1129 /*
759 float distanceAboveGround = pos.Z - terrainHeight; 1130 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
760 if (distanceAboveGround > 2f) 1131 distanceAboveGround = VehiclePosition.Z - targetHeight;
1132 // Not colliding if the vehicle is off the ground
1133 if (!Prim.IsColliding)
761 { 1134 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1135 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 1136 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
765 } 1137 }
766 // TODO: this calculation is all wrong. From the description at 1138 // TODO: this calculation is wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1139 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 1140 // has a decay factor. This says this force should
769 // be computed with a motor. 1141 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 1142 // TODO: add interaction with banking.
771 Prim.LocalID, distanceAboveGround, downForce); 1143 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
772 } 1144 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
773 #endregion // downForce 1145 */
774 1146
775 // If not changing some axis, reduce out velocity 1147 // Another approach is to measure if we're going up. If going up and not colliding,
776 if ((m_flags & (VehicleFlag.NO_X)) != 0) 1148 // the vehicle is in the air. Fix that by pushing down.
777 m_newVelocity.X = 0; 1149 if (!Prim.IsColliding && VehicleVelocity.Z > 0.1)
778 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 1150 {
779 m_newVelocity.Y = 0; 1151 // Get rid of any of the velocity vector that is pushing us up.
780 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 1152 float upVelocity = VehicleVelocity.Z;
781 m_newVelocity.Z = 0; 1153 VehicleVelocity += new Vector3(0, 0, -upVelocity);
782 1154
783 // Clamp REALLY high or low velocities 1155 /*
784 if (m_newVelocity.LengthSquared() > 1e6f) 1156 // If we're pointed up into the air, we should nose down
785 { 1157 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
786 m_newVelocity /= m_newVelocity.Length(); 1158 // The rotation around the Y axis is pitch up or down
787 m_newVelocity *= 1000f; 1159 if (pointingDirection.Y > 0.01f)
788 } 1160 {
789 else if (m_newVelocity.LengthSquared() < 1e-6f) 1161 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
790 m_newVelocity = Vector3.Zero; 1162 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
791 1163 // Rotate into world coordinates and apply to vehicle
792 // Stuff new linear velocity into the vehicle 1164 angularCorrectionVector *= VehicleOrientation;
793 Prim.ForceVelocity = m_newVelocity; 1165 VehicleAddAngularForce(angularCorrectionVector);
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG 1166 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
795 1167 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
796 Vector3 totalDownForce = downForce + grav; 1168 }
797 if (totalDownForce != Vector3.Zero) 1169 */
798 { 1170 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
799 Prim.AddForce(totalDownForce * m_vehicleMass, false); 1171 Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false); 1172 }
801 } 1173 }
1174 }
802 1175
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", 1176 private void ApplyGravity(float pTimeStep)
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); 1177 {
1178 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1179 VehicleAddForce(appliedGravity);
805 1180
806 } // end MoveLinear() 1181 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},appliedForce-{2}",
1182 Prim.LocalID, m_VehicleGravity, appliedGravity);
1183 }
807 1184
808 // ======================================================================= 1185 // =======================================================================
1186 // =======================================================================
809 // Apply the effect of the angular motor. 1187 // Apply the effect of the angular motor.
1188 // The 'contribution' is how much angular correction velocity each function wants.
1189 // All the contributions are added together and the resulting velocity is
1190 // set directly on the vehicle.
810 private void MoveAngular(float pTimestep) 1191 private void MoveAngular(float pTimestep)
811 { 1192 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 1193 // VehicleRotationalVelocity = Vector3.Zero;
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
831 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}",
832 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
833 }
834 else
835 {
836 m_angularMotorVelocity = Vector3.Zero;
837 }
838
839 #region Vertical attactor
840
841 Vector3 vertattr = Vector3.Zero;
842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844
845 // If vertical attaction timescale is reasonable and we applied an angular force last time...
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
847 {
848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
849 if (Prim.IsColliding)
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
851
852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
853
854 // Create a vector of the vehicle "up" in world coordinates
855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
859 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
860 // modulated to prevent a stable inverted body.
861
862 // Error is 0 (no error) to +/- 2 (max error)
863 if (verticalError.Z < 0.0f)
864 {
865 verticalError.X = 2.0f - verticalError.X;
866 verticalError.Y = 2.0f - verticalError.Y;
867 }
868 // scale it by VAservo (timestep and timescale)
869 verticalError = verticalError * VAservo;
870
871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
873 // Z is not changed.
874 vertattr.X = verticalError.Y;
875 vertattr.Y = - verticalError.X;
876 vertattr.Z = 0f;
877 1194
878 // scaling appears better usingsquare-law 1195 ComputeAngularTurning(pTimestep);
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 1196
884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", 1197 ComputeAngularVerticalAttraction();
885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
886 1198
887 } 1199 ComputeAngularDeflection();
888 #endregion // Vertical attactor
889 1200
890 #region Deflection 1201 ComputeAngularBanking();
891 1202
892 if (m_angularDeflectionEfficiency != 0) 1203 // ==================================================================
1204 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.01f))
893 { 1205 {
894 // Compute a scaled vector that points in the preferred axis (X direction) 1206 // The vehicle is not adding anything angular wise.
895 Vector3 scaledDefaultDirection = 1207 VehicleRotationalVelocity = Vector3.Zero;
896 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); 1208 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
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 } 1209 }
909 1210 else
910 #endregion
911
912 #region Banking
913
914 if (m_bankingEfficiency != 0)
915 { 1211 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1212 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 } 1213 }
963 1214
964 #endregion 1215 // ==================================================================
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 1216 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero) 1217 if (m_linearMotorOffset != Vector3.Zero)
975 { 1218 {
@@ -985,8 +1228,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
985 // 1228 //
986 // The torque created is the linear velocity crossed with the offset 1229 // The torque created is the linear velocity crossed with the offset
987 1230
988 // NOTE: this computation does should be in the linear section 1231 // TODO: this computation should be in the linear section
989 // because there we know the impulse being applied. 1232 // because that is where we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero; 1233 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); 1234 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X)) 1235 if (float.IsNaN(torqueFromOffset.X))
@@ -995,47 +1238,213 @@ namespace OpenSim.Region.Physics.BulletSPlugin
995 torqueFromOffset.Y = 0; 1238 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z)) 1239 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0; 1240 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass; 1241
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true); 1242 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1243 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 } 1244 }
1002 1245
1003 #endregion 1246 }
1004 1247
1248 private void ComputeAngularTurning(float pTimestep)
1249 {
1250 // The user wants this many radians per second angular change?
1251 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation);
1252 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1253
1254 // ==================================================================
1255 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1256 // This flag prevents linear deflection parallel to world z-axis. This is useful
1257 // for preventing ground vehicles with large linear deflection, like bumper cars,
1258 // from climbing their linear deflection into the sky.
1259 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1260 // TODO: This is here because this is where ODE put it but documentation says it
1261 // is a linear effect. Where should this check go?
1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1262 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1006 { 1263 {
1007 m_lastAngularVelocity.X = 0; 1264 angularMotorContributionV.X = 0f;
1008 m_lastAngularVelocity.Y = 0; 1265 angularMotorContributionV.Y = 0f;
1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1266 }
1267
1268 VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
1269 VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
1270 }
1271
1272 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1273 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1274 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1275 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1276 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1277 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1278 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1279 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1280 public void ComputeAngularVerticalAttraction()
1281 {
1282 // If vertical attaction timescale is reasonable
1283 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1284 {
1285 Vector3 vertContributionV = Vector3.Zero;
1286
1287 // Take a vector pointing up and convert it from world to vehicle relative coords.
1288 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1289
1290 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1291 // is now:
1292 // leaning to one side: rotated around the X axis with the Y value going
1293 // from zero (nearly straight up) to one (completely to the side)) or
1294 // leaning front-to-back: rotated around the Y axis with the value of X being between
1295 // zero and one.
1296 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1297
1298 // Y error means needed rotation around X axis and visa versa.
1299 // Since the error goes from zero to one, the asin is the corresponding angle.
1300 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1301 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1302 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1303
1304 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1305 if (verticalError.Z < 0f)
1306 {
1307 vertContributionV.X += PIOverFour;
1308 // vertContribution.Y -= PIOverFour;
1309 }
1310
1311 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1312 // Correction happens over a number of seconds.
1313 Vector3 unscaledContrib = vertContributionV; // DEBUG DEBUG
1314 vertContributionV /= m_verticalAttractionTimescale;
1315
1316 VehicleRotationalVelocity += vertContributionV * VehicleOrientation;
1317
1318 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1319 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1010 } 1320 }
1321 }
1322
1323 // Angular correction to correct the direction the vehicle is pointing to be
1324 // the direction is should want to be pointing.
1325 // The vehicle is moving in some direction and correct its orientation to it is pointing
1326 // in that direction.
1327 // TODO: implement reference frame.
1328 public void ComputeAngularDeflection()
1329 {
1330 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1331 // approximately the same X or Y correction. When added together (when contributions are combined)
1332 // this creates an over-correction and then wabbling as the target is overshot.
1333 // TODO: rethink how the different correction computations inter-relate.
1011 1334
1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1335 if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1013 { 1336 {
1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1337 Vector3 deflectContributionV = Vector3.Zero;
1015 Prim.ZeroAngularMotion(true); 1338
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1339 // The direction the vehicle is moving
1340 Vector3 movingDirection = VehicleVelocity;
1341 movingDirection.Normalize();
1342
1343 // If the vehicle is going backward, it is still pointing forward
1344 movingDirection *= Math.Sign(VehicleForwardSpeed);
1345
1346 // The direction the vehicle is pointing
1347 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1348 pointingDirection.Normalize();
1349
1350 // The difference between what is and what should be.
1351 Vector3 deflectionError = movingDirection - pointingDirection;
1352
1353 // Don't try to correct very large errors (not our job)
1354 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1355 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1356 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1357 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1358 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1359 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1360
1361 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1362
1363 // Scale the correction by recovery timescale and efficiency
1364 deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency;
1365 deflectContributionV /= m_angularDeflectionTimescale;
1366
1367 VehicleRotationalVelocity += deflectContributionV * VehicleOrientation;
1368
1369 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1370 Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1371 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1372 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1017 } 1373 }
1018 else 1374 }
1375
1376 // Angular change to rotate the vehicle around the Z axis when the vehicle
1377 // is tipped around the X axis.
1378 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1379 // The vertical attractor feature must be enabled in order for the banking behavior to
1380 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1381 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1382 // of the yaw effect will be proportional to the
1383 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1384 // velocity along its preferred axis of motion.
1385 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1386 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1387 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1388 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1389 // Negating the banking coefficient will make it so that the vehicle leans to the
1390 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1391 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1392 // banking vehicles do what you want rather than what the laws of physics allow.
1393 // For example, consider a real motorcycle...it must be moving forward in order for
1394 // it to turn while banking, however video-game motorcycles are often configured
1395 // to turn in place when at a dead stop--because they are often easier to control
1396 // that way using the limited interface of the keyboard or game controller. The
1397 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1398 // banking by functioning as a slider between a banking that is correspondingly
1399 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1400 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1401 // to "dynamic" where the banking is also proportional to its velocity along its
1402 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1403 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1404 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1405 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1406 // make a sluggish vehicle by giving it a timescale of several seconds.
1407 public void ComputeAngularBanking()
1408 {
1409 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1019 { 1410 {
1020 // Apply to the body. 1411 Vector3 bankingContributionV = Vector3.Zero;
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless. 1412
1022 // Since we are stuffing the angular velocity directly into the object, the computed 1413 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1023 // velocity needs to be scaled by the timestep. 1414 // As the vehicle rolls to the right or left, the Y value will increase from
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); 1415 // zero (straight up) to 1 or -1 (full tilt right or left)
1025 Prim.ForceRotationalVelocity = applyAngularForce; 1416 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1026 1417
1027 // Decay the angular movement for next time 1418 // Figure out the yaw value for this much roll.
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; 1419 // Squared because that seems to give a good value
1029 m_lastAngularVelocity *= Vector3.One - decayamount; 1420 float yawAngle = (float)Math.Asin(rollComponents.Y * rollComponents.Y) * m_bankingEfficiency;
1030 1421
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", 1422 // actual error = static turn error + dynamic turn error
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); 1423 float mixedYawAngle = yawAngle * (1f - m_bankingMix) + yawAngle * m_bankingMix * VehicleForwardSpeed;
1424
1425 // TODO: the banking effect should not go to infinity but what to limit it to?
1426 mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f);
1427
1428 // Build the force vector to change rotation from what it is to what it should be
1429 bankingContributionV.Z = -mixedYawAngle;
1430
1431 // Don't do it all at once.
1432 bankingContributionV /= m_bankingTimescale;
1433
1434 VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
1435
1436 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1437 Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1033 } 1438 }
1034 } //end MoveAngular 1439 }
1035 1440
1441 // This is from previous instantiations of XXXDynamics.cs.
1442 // Applies roll reference frame.
1443 // TODO: is this the right way to separate the code to do this operation?
1444 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1445 internal void LimitRotation(float timestep)
1037 { 1446 {
1038 Quaternion rotq = Prim.ForceOrientation; 1447 Quaternion rotq = VehicleOrientation;
1039 Quaternion m_rot = rotq; 1448 Quaternion m_rot = rotq;
1040 if (m_RollreferenceFrame != Quaternion.Identity) 1449 if (m_RollreferenceFrame != Quaternion.Identity)
1041 { 1450 {
@@ -1063,12 +1472,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1063 } 1472 }
1064 if (rotq != m_rot) 1473 if (rotq != m_rot)
1065 { 1474 {
1066 Prim.ForceOrientation = m_rot; 1475 VehicleOrientation = m_rot;
1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1476 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1068 } 1477 }
1069 1478
1070 } 1479 }
1071 1480
1481 private float ClampInRange(float low, float val, float high)
1482 {
1483 return Math.Max(low, Math.Min(val, high));
1484 // return Utils.Clamp(val, low, high);
1485 }
1486
1072 // Invoke the detailed logger and output something if it's enabled. 1487 // Invoke the detailed logger and output something if it's enabled.
1073 private void VDetailLog(string msg, params Object[] args) 1488 private void VDetailLog(string msg, params Object[] args)
1074 { 1489 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 0df4310..1e3e5d8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,6 +32,15 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35
36// A BSPrim can get individual information about its linkedness attached
37// to it through an instance of a subclass of LinksetInfo.
38// Each type of linkset will define the information needed for its type.
39public abstract class BSLinksetInfo
40{
41 public virtual void Clear() { }
42}
43
35public abstract class BSLinkset 44public abstract class BSLinkset
36{ 45{
37 // private static string LogHeader = "[BULLETSIM LINKSET]"; 46 // private static string LogHeader = "[BULLETSIM LINKSET]";
@@ -47,7 +56,7 @@ public abstract class BSLinkset
47 { 56 {
48 BSLinkset ret = null; 57 BSLinkset ret = null;
49 58
50 switch ((int)physScene.Params.linksetImplementation) 59 switch ((int)BSParam.LinksetImplementation)
51 { 60 {
52 case (int)LinksetImplementation.Constraint: 61 case (int)LinksetImplementation.Constraint:
53 ret = new BSLinksetConstraints(physScene, parent); 62 ret = new BSLinksetConstraints(physScene, parent);
@@ -87,22 +96,8 @@ public abstract class BSLinkset
87 return BSPhysicsShapeType.SHAPE_UNKNOWN; 96 return BSPhysicsShapeType.SHAPE_UNKNOWN;
88 } 97 }
89 98
90 // Linksets move around the children so the linkset might need to compute the child position
91 public virtual OMV.Vector3 Position(BSPhysObject member)
92 { return member.RawPosition; }
93 public virtual OMV.Quaternion Orientation(BSPhysObject member)
94 { return member.RawOrientation; }
95 // TODO: does this need to be done for Velocity and RotationalVelocityy?
96
97 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 99 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
98 protected float m_mass; 100 public float LinksetMass { get; protected set; }
99 public float LinksetMass
100 {
101 get
102 {
103 return m_mass;
104 }
105 }
106 101
107 public virtual bool LinksetIsColliding { get { return false; } } 102 public virtual bool LinksetIsColliding { get { return false; } }
108 103
@@ -116,7 +111,7 @@ public abstract class BSLinkset
116 get { return ComputeLinksetGeometricCenter(); } 111 get { return ComputeLinksetGeometricCenter(); }
117 } 112 }
118 113
119 protected void Initialize(BSScene scene, BSPhysObject parent) 114 protected BSLinkset(BSScene scene, BSPhysObject parent)
120 { 115 {
121 // A simple linkset of one (no children) 116 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++; 117 LinksetID = m_nextLinksetID++;
@@ -126,7 +121,8 @@ public abstract class BSLinkset
126 PhysicsScene = scene; 121 PhysicsScene = scene;
127 LinksetRoot = parent; 122 LinksetRoot = parent;
128 m_children = new HashSet<BSPhysObject>(); 123 m_children = new HashSet<BSPhysObject>();
129 m_mass = parent.RawMass; 124 LinksetMass = parent.RawMass;
125 Rebuilding = false;
130 } 126 }
131 127
132 // Link to a linkset where the child knows the parent. 128 // Link to a linkset where the child knows the parent.
@@ -140,7 +136,7 @@ public abstract class BSLinkset
140 // Don't add the root to its own linkset 136 // Don't add the root to its own linkset
141 if (!IsRoot(child)) 137 if (!IsRoot(child))
142 AddChildToLinkset(child); 138 AddChildToLinkset(child);
143 m_mass = ComputeLinksetMass(); 139 LinksetMass = ComputeLinksetMass();
144 } 140 }
145 return this; 141 return this;
146 } 142 }
@@ -156,13 +152,15 @@ public abstract class BSLinkset
156 if (IsRoot(child)) 152 if (IsRoot(child))
157 { 153 {
158 // Cannot remove the root from a linkset. 154 // Cannot remove the root from a linkset.
155 child.PositionDisplacement = OMV.Vector3.Zero;
159 return this; 156 return this;
160 } 157 }
161 RemoveChildFromLinkset(child); 158 RemoveChildFromLinkset(child);
162 m_mass = ComputeLinksetMass(); 159 LinksetMass = ComputeLinksetMass();
163 } 160 }
164 161
165 // The child is down to a linkset of just itself 162 // The child is down to a linkset of just itself
163 child.PositionDisplacement = OMV.Vector3.Zero;
166 return BSLinkset.Factory(PhysicsScene, child); 164 return BSLinkset.Factory(PhysicsScene, child);
167 } 165 }
168 166
@@ -219,7 +217,7 @@ public abstract class BSLinkset
219 // I am the root of a linkset and a new child is being added 217 // I am the root of a linkset and a new child is being added
220 // Called while LinkActivity is locked. 218 // Called while LinkActivity is locked.
221 protected abstract void AddChildToLinkset(BSPhysObject child); 219 protected abstract void AddChildToLinkset(BSPhysObject child);
222 220
223 // I am the root of a linkset and one of my children is being removed. 221 // 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. 222 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child); 223 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
@@ -227,7 +225,14 @@ public abstract class BSLinkset
227 // When physical properties are changed the linkset needs to recalculate 225 // When physical properties are changed the linkset needs to recalculate
228 // its internal properties. 226 // its internal properties.
229 // May be called at runtime or taint-time. 227 // May be called at runtime or taint-time.
230 public abstract void Refresh(BSPhysObject requestor); 228 public virtual void Refresh(BSPhysObject requestor)
229 {
230 LinksetMass = ComputeLinksetMass();
231 }
232
233 // Flag denoting the linkset is in the process of being rebuilt.
234 // Used to know not the schedule a rebuild in the middle of a rebuild.
235 protected bool Rebuilding { get; set; }
231 236
232 // The object is going dynamic (physical). Do any setup necessary 237 // The object is going dynamic (physical). Do any setup necessary
233 // for a dynamic linkset. 238 // for a dynamic linkset.
@@ -245,8 +250,9 @@ public abstract class BSLinkset
245 250
246 // Called when a parameter update comes from the physics engine for any object 251 // Called when a parameter update comes from the physics engine for any object
247 // of the linkset is received. 252 // of the linkset is received.
253 // Passed flag is update came from physics engine (true) or the user (false).
248 // Called at taint-time!! 254 // Called at taint-time!!
249 public abstract void UpdateProperties(BSPhysObject physObject); 255 public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject physObject);
250 256
251 // Routine used when rebuilding the body of the root of the linkset 257 // Routine used when rebuilding the body of the root of the linkset
252 // Destroy all the constraints have have been made to root. 258 // Destroy all the constraints have have been made to root.
@@ -255,11 +261,6 @@ public abstract class BSLinkset
255 // Called at taint-time!! 261 // Called at taint-time!!
256 public abstract bool RemoveBodyDependencies(BSPrim child); 262 public abstract bool RemoveBodyDependencies(BSPrim child);
257 263
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
263 // ================================================================ 264 // ================================================================
264 protected virtual float ComputeLinksetMass() 265 protected virtual float ComputeLinksetMass()
265 { 266 {
@@ -306,7 +307,7 @@ public abstract class BSLinkset
306 307
307 foreach (BSPhysObject bp in m_children) 308 foreach (BSPhysObject bp in m_children)
308 { 309 {
309 com += bp.Position * bp.RawMass; 310 com += bp.Position;
310 } 311 }
311 com /= (m_children.Count + 1); 312 com /= (m_children.Count + 1);
312 } 313 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index b9c2cf9..2c8dd23 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,22 +28,79 @@ 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, BSPhysObject root, BSPhysObject 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, BSPhysObject parent) : base(scene, parent)
40 { 97 {
41 base.Initialize(scene, parent);
42 } 98 }
43 99
44 // For compound implimented linksets, if there are children, use compound shape for the root. 100 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 101 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 { 102 {
103 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 104 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 105 if (IsRoot(requestor) && HasAnyChildren)
49 { 106 {
@@ -55,27 +112,33 @@ public sealed class BSLinksetCompound : BSLinkset
55 112
56 // When physical properties are changed the linkset needs to recalculate 113 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 114 // its internal properties.
58 // This is queued in the 'post taint' queue so the
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor) 115 public override void Refresh(BSPhysObject requestor)
61 { 116 {
62 // External request for Refresh (from BSPrim) is not necessary 117 base.Refresh(requestor);
63 // InternalRefresh(requestor); 118
119 // Something changed so do the rebuilding thing
120 // ScheduleRebuild();
64 } 121 }
65 122
66 private void InternalRefresh(BSPhysObject requestor) 123 // Schedule a refresh to happen after all the other taint processing.
124 private void ScheduleRebuild(BSPhysObject requestor)
67 { 125 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 126 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
69 // Queue to happen after all the other taint processing 127 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 128 // When rebuilding, it is possible to set properties that would normally require a rebuild.
129 // If already rebuilding, don't request another rebuild.
130 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
131 if (!Rebuilding && HasAnyChildren)
71 { 132 {
72 if (IsRoot(requestor) && HasAnyChildren) 133 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
73 RecomputeLinksetCompound(); 134 {
74 }); 135 if (HasAnyChildren)
136 RecomputeLinksetCompound();
137 });
138 }
75 } 139 }
76 140
77 // The object is going dynamic (physical). Do any setup necessary 141 // 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 142 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed. 143 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object. 144 // Return 'true' if any properties updated on the passed object.
@@ -84,12 +147,22 @@ public sealed class BSLinksetCompound : BSLinkset
84 { 147 {
85 bool ret = false; 148 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 149 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 150 if (IsRoot(child))
151 {
152 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
153 ScheduleRebuild(LinksetRoot);
154 }
155 else
88 { 156 {
89 // Physical children are removed from the world as the shape ofthe root compound 157 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 158 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 159 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 160 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
161 // We don't want collisions from the old linkset children.
162 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
163
164 child.PhysBody.collisionType = CollisionType.LinksetChild;
165
93 ret = true; 166 ret = true;
94 } 167 }
95 return ret; 168 return ret;
@@ -104,33 +177,92 @@ public sealed class BSLinksetCompound : BSLinkset
104 { 177 {
105 bool ret = false; 178 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 179 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 180 if (IsRoot(child))
181 {
182 ScheduleRebuild(LinksetRoot);
183 }
184 else
108 { 185 {
109 // The non-physical children can come back to life. 186 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 187 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 188
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 189 child.PhysBody.collisionType = CollisionType.LinksetChild;
190
191 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
192 PhysicsScene.PE.Activate(child.PhysBody, false);
113 ret = true; 193 ret = true;
114 } 194 }
115 return ret; 195 return ret;
116 } 196 }
117 197
118 // Called at taint-time!! 198 // '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) 199 // Called at taint-time.
120 { 200 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject 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 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
129 }
130
131 public override OMV.Quaternion Orientation(BSPhysObject member)
132 { 201 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); 202 // The user moving a child around requires the rebuilding of the linkset compound shape
203 // One problem is this happens when a border is crossed -- the simulator implementation
204 // stores the position into the group which causes the move of the object
205 // but it also means all the child positions get updated.
206 // What would cause an unnecessary rebuild so we make sure the linkset is in a
207 // region before bothering to do a rebuild.
208 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
209 {
210 // If a child of the linkset is updating only the position or rotation, that can be done
211 // without rebuilding the linkset.
212 // If a handle for the child can be fetch, we update the child here. If a rebuild was
213 // scheduled by someone else, the rebuild will just replace this setting.
214
215 bool updatedChild = false;
216 // Anything other than updating position or orientation usually means a physical update
217 // and that is caused by us updating the object.
218 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
219 {
220 // Gather the child info. It might not be there if the linkset is in transition.
221 BSLinksetCompoundInfo lsi = updated.LinksetInfo as BSLinksetCompoundInfo;
222 if (LinksetRoot.PhysShape.HasPhysicalShape && lsi != null)
223 {
224 if (PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
225 {
226 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, lsi.Index);
227 if (linksetChildShape.HasPhysicalShape)
228 {
229 // Compute the offset from the center-of-gravity
230 BSLinksetCompoundInfo newLsi = new BSLinksetCompoundInfo(lsi.Index, LinksetRoot, updated, LinksetRoot.PositionDisplacement);
231 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, lsi.Index,
232 newLsi.OffsetFromCenterOfMass,
233 newLsi.OffsetRot,
234 true /* shouldRecalculateLocalAabb */);
235 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1}newLsi={2}",
236 updated.LocalID, whichUpdated, newLsi);
237 updated.LinksetInfo = newLsi;
238 updatedChild = true;
239 }
240 else // DEBUG DEBUG
241 { // DEBUG DEBUG
242 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
243 updated.LocalID, linksetChildShape);
244 } // DEBUG DEBUG
245 }
246 else // DEBUG DEBUG
247 { // DEBUG DEBUG
248 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,notCompound", updated.LocalID);
249 } // DEBUG DEBUG
250 }
251 else // DEBUG DEBUG
252 { // DEBUG DEBUG
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,rootPhysShape={1},lsi={2}",
254 updated.LocalID, LinksetRoot.PhysShape, lsi == null ? "NULL" : lsi.ToString());
255 } // DEBUG DEBUG
256 if (!updatedChild)
257 {
258 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
259 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
260 updated.LocalID, whichUpdated);
261 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
262 ScheduleRebuild(updated);
263 }
264 }
265 }
134 } 266 }
135 267
136 // Routine called when rebuilding the body of some member of the linkset. 268 // Routine called when rebuilding the body of some member of the linkset.
@@ -142,24 +274,55 @@ public sealed class BSLinksetCompound : BSLinkset
142 bool ret = false; 274 bool ret = false;
143 275
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 276 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); 277 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child));
146 278
147 if (!IsRoot(child)) 279 if (!IsRoot(child))
148 { 280 {
149 // Cause the current shape to be freed and the new one to be built. 281 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 282 // its position in the linkset.
151 ret = true; 283 RecomputeChildWorldPosition(child, true);
152 } 284 }
153 285
286 // Cannot schedule a refresh/rebuild here because this routine is called when
287 // the linkset is being rebuilt.
288 // InternalRefresh(LinksetRoot);
289
154 return ret; 290 return ret;
155 } 291 }
156 292
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 293 // 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. 294 // root shape. The linkset then moves around but this does not move the actual child
159 // Called at taint-time!! 295 // prim. The child prim's location must be recomputed based on the location of the root shape.
160 public override void RestoreBodyDependencies(BSPrim child) 296 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
161 { 297 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 298 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
299 if (lci != null)
300 {
301 if (inTaintTime)
302 {
303 OMV.Vector3 oldPos = child.RawPosition;
304 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
305 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
306 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
307 child.LocalID, oldPos, lci, child.RawPosition);
308 }
309 else
310 {
311 // TaintedObject is not used here so the raw position is set now and not at taint-time.
312 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
313 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
314 }
315 }
316 else
317 {
318 // This happens when children have been added to the linkset but the linkset
319 // has not been constructed yet. So like, at taint time, adding children to a linkset
320 // and then changing properties of the children (makePhysical, for instance)
321 // but the post-print action of actually rebuilding the linkset has not yet happened.
322 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
323 // LogHeader, child.LocalID);
324 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
325 }
163 } 326 }
164 327
165 // ================================================================ 328 // ================================================================
@@ -174,24 +337,25 @@ public sealed class BSLinksetCompound : BSLinkset
174 337
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 338 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176 339
177 // Cause constraints and assorted properties to be recomputed before the next simulation step. 340 // Rebuild the compound shape with the new child shape included
178 InternalRefresh(LinksetRoot); 341 ScheduleRebuild(child);
179 } 342 }
180 return; 343 return;
181 } 344 }
182 345
183 // Remove the specified child from the linkset. 346 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 347 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 348 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 { 349 {
187 if (m_children.Remove(child)) 350 if (m_children.Remove(child))
188 { 351 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 352 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID, 353 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), 354 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 355 child.LocalID, child.PhysBody.AddrString);
193 356
194 // Cause the child's body to be rebuilt and thus restored to normal operation 357 // Cause the child's body to be rebuilt and thus restored to normal operation
358 RecomputeChildWorldPosition(child, false);
195 child.ForceBodyShapeRebuild(false); 359 child.ForceBodyShapeRebuild(false);
196 360
197 if (!HasAnyChildren) 361 if (!HasAnyChildren)
@@ -201,8 +365,8 @@ public sealed class BSLinksetCompound : BSLinkset
201 } 365 }
202 else 366 else
203 { 367 {
204 // Schedule a rebuild of the linkset before the next simulation tick. 368 // Rebuild the compound shape with the child removed
205 InternalRefresh(LinksetRoot); 369 ScheduleRebuild(LinksetRoot);
206 } 370 }
207 } 371 }
208 return; 372 return;
@@ -213,63 +377,112 @@ public sealed class BSLinksetCompound : BSLinkset
213 // Constraint linksets are rebuilt every time. 377 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart. 378 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!! 379 // Called at taint time!!
380 private bool disableCOM = false; // disable until we get this debugged
216 private void RecomputeLinksetCompound() 381 private void RecomputeLinksetCompound()
217 { 382 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 383 try
219 LinksetRoot.ForceBodyShapeRebuild(true);
220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 // Add a shape for each of the other children in the linkset
225 ForEachMember(delegate(BSPhysObject cPrim)
226 { 384 {
227 if (!IsRoot(cPrim)) 385 // Suppress rebuilding while rebuilding
386 Rebuilding = true;
387
388 // Cause the root shape to be rebuilt as a compound object with just the root in it
389 LinksetRoot.ForceBodyShapeRebuild(true);
390
391 // The center of mass for the linkset is the geometric center of the group.
392 // Compute a displacement for each component so it is relative to the center-of-mass.
393 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
394 OMV.Vector3 centerOfMass;
395 OMV.Vector3 centerDisplacement = OMV.Vector3.Zero;
396 if (disableCOM) // DEBUG DEBUG
397 { // DEBUG DEBUG
398 centerOfMass = LinksetRoot.RawPosition; // DEBUG DEBUG
399 LinksetRoot.PositionDisplacement = OMV.Vector3.Zero;
400 } // DEBUG DEBUG
401 else
228 { 402 {
229 // Each child position and rotation is given relative to the root. 403 centerOfMass = ComputeLinksetCenterOfMass();
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 404 // 'centerDisplacement' is the value to *add* to all the shape offsets
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; 405 centerDisplacement = LinksetRoot.RawPosition - centerOfMass;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; 406
407 // Since we're displacing the center of the shape, we need to move the body in the world
408 LinksetRoot.PositionDisplacement = centerDisplacement;
409
410 // This causes the root prim position to be set properly based on the new PositionDisplacement
411 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
412 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
413 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false);
414 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
415 LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement);
416 }
233 417
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 418 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 419 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
236 420
237 if (cPrim.PhysShape.isNativeShape) 421 // Add a shape for each of the other children in the linkset
238 { 422 int memberIndex = 1;
239 // Native shapes are not shared so we need to create a new one. 423 ForEachMember(delegate(BSPhysObject cPrim)
240 // A mesh or hull is created because scale is not available on a native shape. 424 {
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) 425 if (!IsRoot(cPrim))
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 }
249 else
250 { 426 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 427 // Compute the displacement of the child from the root of the linkset.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 428 // This info is saved in the child prim so the relationship does not
429 // change over time and the new child position can be computed
430 // when the linkset is being disassembled (the linkset may have moved).
431 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
432 if (lci == null)
253 { 433 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 434 lci = new BSLinksetCompoundInfo(memberIndex, LinksetRoot, cPrim, centerDisplacement);
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 435 cPrim.LinksetInfo = lci;
436 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
256 } 437 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 return false; // 'false' says to move onto the next child in the list
261 });
262 438
263 // With all of the linkset packed into the root prim, it has the mass of everyone. 439 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},lci={3}",
264 float linksetMass = LinksetMass; 440 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci);
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
266 441
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 442 if (cPrim.PhysShape.isNativeShape)
443 {
444 // A native shape is turned into a hull collision shape because native
445 // shapes are not shared so we have to hullify it so it will be tracked
446 // and freed at the correct time. This also solves the scaling problem
447 // (native shapes scaled but hull/meshes are assumed to not be).
448 // TODO: decide of the native shape can just be used in the compound shape.
449 // Use call to CreateGeomNonSpecial().
450 BulletShape saveShape = cPrim.PhysShape;
451 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
452 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
453 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
454 BulletShape newShape = cPrim.PhysShape;
455 cPrim.PhysShape = saveShape;
456 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
457 }
458 else
459 {
460 // For the shared shapes (meshes and hulls), just use the shape in the child.
461 // The reference count added here will be decremented when the compound shape
462 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
463 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
464 {
465 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
466 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
467 }
468 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
469 }
470 lci.Index = memberIndex;
471 memberIndex++;
472 }
473 return false; // 'false' says to move onto the next child in the list
474 });
268 475
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. 476 // With all of the linkset packed into the root prim, it has the mass of everyone.
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, 477 LinksetMass = ComputeLinksetMass();
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); 478 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
479 }
480 finally
481 {
482 Rebuilding = false;
483 }
272 484
485 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
273 } 486 }
274} 487}
275} \ No newline at end of file 488} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index c855fda..3011465 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38 38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) 39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 40 {
41 base.Initialize(scene, parent);
42 } 41 }
43 42
44 // When physical properties are changed the linkset needs to recalculate 43 // When physical properties are changed the linkset needs to recalculate
@@ -47,12 +46,17 @@ public sealed class BSLinksetConstraints : BSLinkset
47 // refresh will happen once after all the other taints are applied. 46 // refresh will happen once after all the other taints are applied.
48 public override void Refresh(BSPhysObject requestor) 47 public override void Refresh(BSPhysObject requestor)
49 { 48 {
50 // Queue to happen after all the other taint processing 49 base.Refresh(requestor);
51 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() 50
52 { 51 if (HasAnyChildren && IsRoot(requestor))
53 if (HasAnyChildren && IsRoot(requestor)) 52 {
54 RecomputeLinksetConstraints(); 53 // Queue to happen after all the other taint processing
55 }); 54 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
55 {
56 if (HasAnyChildren && IsRoot(requestor))
57 RecomputeLinksetConstraints();
58 });
59 }
56 } 60 }
57 61
58 // The object is going dynamic (physical). Do any setup necessary 62 // The object is going dynamic (physical). Do any setup necessary
@@ -79,23 +83,11 @@ public sealed class BSLinksetConstraints : BSLinkset
79 } 83 }
80 84
81 // Called at taint-time!! 85 // Called at taint-time!!
82 public override void UpdateProperties(BSPhysObject updated) 86 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject 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.
@@ -106,7 +98,7 @@ public sealed class BSLinksetConstraints : BSLinkset
106 bool ret = false; 98 bool ret = false;
107 99
108 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", 100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
109 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X")); 101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
110 102
111 lock (m_linksetActivityLock) 103 lock (m_linksetActivityLock)
112 { 104 {
@@ -118,14 +110,6 @@ 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.
@@ -155,8 +139,8 @@ public sealed class BSLinksetConstraints : BSLinkset
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 {
@@ -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.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
243 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), 227 constrain.TranslationalLimitMotor(BSParam.BoolNumeric(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 }
@@ -260,14 +244,14 @@ public sealed class BSLinksetConstraints : BSLinkset
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
@@ -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 (BSPhysObject 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..92d62ff
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -0,0 +1,200 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using System.Reflection;
31using Nini.Config;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public struct MaterialAttributes
37{
38 // Material type values that correspond with definitions for LSL
39 public enum Material : int
40 {
41 Stone = 0,
42 Metal,
43 Glass,
44 Wood,
45 Flesh,
46 Plastic,
47 Rubber,
48 Light,
49 // Hereafter are BulletSim additions
50 Avatar,
51 NumberOfTypes // the count of types in the enum.
52 }
53
54 // Names must be in the order of the above enum.
55 // These names must coorespond to the lower case field names in the MaterialAttributes
56 // structure as reflection is used to select the field to put the value in.
57 public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
58
59 public MaterialAttributes(string t, float d, float f, float r)
60 {
61 type = t;
62 density = d;
63 friction = f;
64 restitution = r;
65 }
66 public string type;
67 public float density;
68 public float friction;
69 public float restitution;
70}
71
72public static class BSMaterials
73{
74 // Attributes for each material type
75 private static readonly MaterialAttributes[] Attributes;
76
77 // Map of material name to material type code
78 public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap;
79
80 static BSMaterials()
81 {
82 // Attribute sets for both the non-physical and physical instances of materials.
83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
84
85 // Map of name to type code.
86 MaterialMap = new Dictionary<string, MaterialAttributes.Material>();
87 MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
88 MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
89 MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
90 MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
91 MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
92 MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
93 MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
94 MaterialMap.Add("Light", MaterialAttributes.Material.Light);
95 MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
96 }
97
98 // This is where all the default material attributes are defined.
99 public static void InitializeFromDefaults(ConfigurationParameters parms)
100 {
101 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
102 float dDensity = parms.defaultDensity;
103 float dFriction = parms.defaultFriction;
104 float dRestitution = parms.defaultRestitution;
105 Attributes[(int)MaterialAttributes.Material.Stone] =
106 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
107 Attributes[(int)MaterialAttributes.Material.Metal] =
108 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
109 Attributes[(int)MaterialAttributes.Material.Glass] =
110 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
111 Attributes[(int)MaterialAttributes.Material.Wood] =
112 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
113 Attributes[(int)MaterialAttributes.Material.Flesh] =
114 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
115 Attributes[(int)MaterialAttributes.Material.Plastic] =
116 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
117 Attributes[(int)MaterialAttributes.Material.Rubber] =
118 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
119 Attributes[(int)MaterialAttributes.Material.Light] =
120 new MaterialAttributes("light",dDensity, dFriction, dRestitution);
121 Attributes[(int)MaterialAttributes.Material.Avatar] =
122 new MaterialAttributes("avatar",3.5f, 0.2f, 0f);
123
124 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
125 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
126 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
127 new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f);
128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
129 new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f);
130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
131 new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f);
132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
133 new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f);
134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
135 new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f);
136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
137 new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f);
138 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
139 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
140 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
141 new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f);
142 }
143
144 // Under the [BulletSim] section, one can change the individual material
145 // attribute values. The format of the configuration parameter is:
146 // <materialName><Attribute>["Physical"] = floatValue
147 // For instance:
148 // [BulletSim]
149 // StoneFriction = 0.2
150 // FleshRestitutionPhysical = 0.8
151 // Materials can have different parameters for their static and
152 // physical instantiations. When setting the non-physical value,
153 // both values are changed. Setting the physical value only changes
154 // the physical value.
155 public static void InitializefromParameters(IConfig pConfig)
156 {
157 foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap)
158 {
159 string matName = kvp.Key;
160 foreach (string attribName in MaterialAttributes.MaterialAttribs)
161 {
162 string paramName = matName + attribName;
163 if (pConfig.Contains(paramName))
164 {
165 float paramValue = pConfig.GetFloat(paramName);
166 SetAttributeValue((int)kvp.Value, attribName, paramValue);
167 // set the physical value also
168 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
169 }
170 paramName += "Physical";
171 if (pConfig.Contains(paramName))
172 {
173 float paramValue = pConfig.GetFloat(paramName);
174 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
175 }
176 }
177 }
178 }
179
180 // Use reflection to set the value in the attribute structure.
181 private static void SetAttributeValue(int matType, string attribName, float val)
182 {
183 MaterialAttributes thisAttrib = Attributes[matType];
184 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
185 if (fieldInfo != null)
186 {
187 fieldInfo.SetValue(thisAttrib, val);
188 Attributes[matType] = thisAttrib;
189 }
190 }
191
192 // Given a material type, return a structure of attributes.
193 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
194 {
195 int ind = (int)type;
196 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
197 return Attributes[ind];
198 }
199}
200}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index bc6e4c4..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..9460daf
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -0,0 +1,657 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Region.Physics.Manager;
32
33using OpenMetaverse;
34using Nini.Config;
35
36namespace OpenSim.Region.Physics.BulletSPlugin
37{
38public static class BSParam
39{
40 // Level of Detail values kept as float because that's what the Meshmerizer wants
41 public static float MeshLOD { get; private set; }
42 public static float MeshMegaPrimLOD { get; private set; }
43 public static float MeshMegaPrimThreshold { get; private set; }
44 public static float SculptLOD { get; private set; }
45
46 public static float MinimumObjectMass { get; private set; }
47 public static float MaximumObjectMass { get; private set; }
48 public static float MaxLinearVelocity { get; private set; }
49 public static float MaxAngularVelocity { get; private set; }
50 public static float MaxAddForceMagnitude { get; private set; }
51
52 public static float LinearDamping { get; private set; }
53 public static float AngularDamping { get; private set; }
54 public static float DeactivationTime { get; private set; }
55 public static float LinearSleepingThreshold { get; private set; }
56 public static float AngularSleepingThreshold { get; private set; }
57 public static float CcdMotionThreshold { get; private set; }
58 public static float CcdSweptSphereRadius { get; private set; }
59 public static float ContactProcessingThreshold { get; private set; }
60
61 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
62 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
63 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
64
65 public static float TerrainImplementation { get; private set; }
66 public static float TerrainFriction { get; private set; }
67 public static float TerrainHitFraction { get; private set; }
68 public static float TerrainRestitution { get; private set; }
69 public static float TerrainCollisionMargin { get; private set; }
70
71 // Avatar parameters
72 public static float AvatarFriction { get; private set; }
73 public static float AvatarStandingFriction { get; private set; }
74 public static float AvatarAlwaysRunFactor { get; private set; }
75 public static float AvatarDensity { get; private set; }
76 public static float AvatarRestitution { get; private set; }
77 public static float AvatarCapsuleWidth { get; private set; }
78 public static float AvatarCapsuleDepth { get; private set; }
79 public static float AvatarCapsuleHeight { get; private set; }
80 public static float AvatarContactProcessingThreshold { get; private set; }
81 public static float AvatarStepHeight { get; private set; }
82 public static float AvatarStepApproachFactor { get; private set; }
83 public static float AvatarStepForceFactor { get; private set; }
84
85 public static float VehicleMaxLinearVelocity { get; private set; }
86 public static float VehicleMaxAngularVelocity { get; private set; }
87 public static float VehicleAngularDamping { get; private set; }
88 public static float VehicleDebuggingEnabled { get; private set; }
89
90 public static float LinksetImplementation { get; private set; }
91 public static float LinkConstraintUseFrameOffset { get; private set; }
92 public static float LinkConstraintEnableTransMotor { get; private set; }
93 public static float LinkConstraintTransMotorMaxVel { get; private set; }
94 public static float LinkConstraintTransMotorMaxForce { get; private set; }
95 public static float LinkConstraintERP { get; private set; }
96 public static float LinkConstraintCFM { get; private set; }
97 public static float LinkConstraintSolverIterations { get; private set; }
98
99 public static float PID_D { get; private set; } // derivative
100 public static float PID_P { get; private set; } // proportional
101
102 // Various constants that come from that other virtual world that shall not be named.
103 public const float MinGravityZ = -1f;
104 public const float MaxGravityZ = 28f;
105 public const float MinFriction = 0f;
106 public const float MaxFriction = 255f;
107 public const float MinDensity = 0.01f;
108 public const float MaxDensity = 22587f;
109 public const float MinRestitution = 0f;
110 public const float MaxRestitution = 1f;
111
112 // ===========================================================================
113 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
114 public delegate float ParamGet(BSScene scene);
115 public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
116 public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
117
118 public struct ParameterDefn
119 {
120 public string name; // string name of the parameter
121 public string desc; // a short description of what the parameter means
122 public float defaultValue; // default value if not specified anywhere else
123 public ParamUser userParam; // get the value from the configuration file
124 public ParamGet getter; // return the current value stored for this parameter
125 public ParamSet setter; // set the current value for this parameter
126 public SetOnObject onObject; // set the value on an object in the physical domain
127 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
128 {
129 name = n;
130 desc = d;
131 defaultValue = v;
132 userParam = u;
133 getter = g;
134 setter = s;
135 onObject = null;
136 }
137 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
138 {
139 name = n;
140 desc = d;
141 defaultValue = v;
142 userParam = u;
143 getter = g;
144 setter = s;
145 onObject = o;
146 }
147 }
148
149 // List of all of the externally visible parameters.
150 // For each parameter, this table maps a text name to getter and setters.
151 // To add a new externally referencable/settable parameter, add the paramter storage
152 // location somewhere in the program and make an entry in this table with the
153 // getters and setters.
154 // It is easiest to find an existing definition and copy it.
155 // Parameter values are floats. Booleans are converted to a floating value.
156 //
157 // A ParameterDefn() takes the following parameters:
158 // -- the text name of the parameter. This is used for console input and ini file.
159 // -- a short text description of the parameter. This shows up in the console listing.
160 // -- a default value (float)
161 // -- a delegate for fetching the parameter from the ini file.
162 // Should handle fetching the right type from the ini file and converting it.
163 // -- a delegate for getting the value as a float
164 // -- a delegate for setting the value from a float
165 // -- an optional delegate to update the value in the world. Most often used to
166 // push the new value to an in-world object.
167 //
168 // The single letter parameters for the delegates are:
169 // s = BSScene
170 // o = BSPhysObject
171 // p = string parameter name
172 // l = localID of referenced object
173 // v = value (float)
174 // cf = parameter configuration class (for fetching values from ini file)
175 private static ParameterDefn[] ParameterDefinitions =
176 {
177 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
178 ConfigurationParameters.numericTrue,
179 (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
180 (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
181 (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
182 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
183 ConfigurationParameters.numericFalse,
184 (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
185 (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
186 (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
187 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
188 ConfigurationParameters.numericTrue,
189 (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
190 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
191 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
192
193 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
194 8f,
195 (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
196 (s) => { return MeshLOD; },
197 (s,p,l,v) => { MeshLOD = v; } ),
198 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
199 16f,
200 (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
201 (s) => { return MeshMegaPrimLOD; },
202 (s,p,l,v) => { MeshMegaPrimLOD = v; } ),
203 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
204 10f,
205 (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
206 (s) => { return MeshMegaPrimThreshold; },
207 (s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
208 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
209 32f,
210 (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
211 (s) => { return SculptLOD; },
212 (s,p,l,v) => { SculptLOD = v; } ),
213
214 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
215 10f,
216 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
217 (s) => { return (float)s.m_maxSubSteps; },
218 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
219 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
220 1f / 60f,
221 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
222 (s) => { return (float)s.m_fixedTimeStep; },
223 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
224 new ParameterDefn("NominalFrameRate", "The base frame rate we claim",
225 55f,
226 (s,cf,p,v) => { s.NominalFrameRate = cf.GetInt(p, (int)v); },
227 (s) => { return (float)s.NominalFrameRate; },
228 (s,p,l,v) => { s.NominalFrameRate = (int)v; } ),
229 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
230 2048f,
231 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
232 (s) => { return (float)s.m_maxCollisionsPerFrame; },
233 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
234 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
235 8000f,
236 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
237 (s) => { return (float)s.m_maxUpdatesPerFrame; },
238 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
239
240 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
241 0.0001f,
242 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
243 (s) => { return (float)MinimumObjectMass; },
244 (s,p,l,v) => { MinimumObjectMass = v; } ),
245 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
246 10000.01f,
247 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
248 (s) => { return (float)MaximumObjectMass; },
249 (s,p,l,v) => { MaximumObjectMass = v; } ),
250 new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
251 1000.0f,
252 (s,cf,p,v) => { MaxLinearVelocity = cf.GetFloat(p, v); },
253 (s) => { return (float)MaxLinearVelocity; },
254 (s,p,l,v) => { MaxLinearVelocity = v; } ),
255 new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
256 1000.0f,
257 (s,cf,p,v) => { MaxAngularVelocity = cf.GetFloat(p, v); },
258 (s) => { return (float)MaxAngularVelocity; },
259 (s,p,l,v) => { MaxAngularVelocity = v; } ),
260 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
261 new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
262 20000.0f,
263 (s,cf,p,v) => { MaxAddForceMagnitude = cf.GetFloat(p, v); },
264 (s) => { return (float)MaxAddForceMagnitude; },
265 (s,p,l,v) => { MaxAddForceMagnitude = v; } ),
266
267 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
268 2200f,
269 (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
270 (s) => { return (float)PID_D; },
271 (s,p,l,v) => { PID_D = v; } ),
272 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
273 900f,
274 (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
275 (s) => { return (float)PID_P; },
276 (s,p,l,v) => { PID_P = v; } ),
277
278 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
279 0.2f,
280 (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
281 (s) => { return s.UnmanagedParams[0].defaultFriction; },
282 (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
283 new ParameterDefn("DefaultDensity", "Density for new objects" ,
284 10.000006836f, // Aluminum g/cm3
285 (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
286 (s) => { return s.UnmanagedParams[0].defaultDensity; },
287 (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
288 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
289 0f,
290 (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
291 (s) => { return s.UnmanagedParams[0].defaultRestitution; },
292 (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
293 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
294 0.04f,
295 (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
296 (s) => { return s.UnmanagedParams[0].collisionMargin; },
297 (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
298 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
299 -9.80665f,
300 (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
301 (s) => { return s.UnmanagedParams[0].gravity; },
302 (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
303 (s,o,v) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,v)); } ),
304
305
306 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
307 0f,
308 (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
309 (s) => { return LinearDamping; },
310 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
311 (s,o,v) => { s.PE.SetDamping(o.PhysBody, v, AngularDamping); } ),
312 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
313 0f,
314 (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
315 (s) => { return AngularDamping; },
316 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
317 (s,o,v) => { s.PE.SetDamping(o.PhysBody, LinearDamping, v); } ),
318 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
319 0.2f,
320 (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
321 (s) => { return DeactivationTime; },
322 (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
323 (s,o,v) => { s.PE.SetDeactivationTime(o.PhysBody, v); } ),
324 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
325 0.8f,
326 (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
327 (s) => { return LinearSleepingThreshold; },
328 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
329 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
330 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
331 1.0f,
332 (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
333 (s) => { return AngularSleepingThreshold; },
334 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
335 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
336 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
337 0.3f, // set to zero to disable
338 (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
339 (s) => { return CcdMotionThreshold; },
340 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
341 (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ),
342 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
343 0.2f,
344 (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
345 (s) => { return CcdSweptSphereRadius; },
346 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
347 (s,o,v) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, v); } ),
348 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
349 0.1f,
350 (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
351 (s) => { return ContactProcessingThreshold; },
352 (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
353 (s,o,v) => { s.PE.SetContactProcessingThreshold(o.PhysBody, v); } ),
354
355 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
356 (float)BSTerrainPhys.TerrainImplementation.Mesh,
357 (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
358 (s) => { return TerrainImplementation; },
359 (s,p,l,v) => { TerrainImplementation = v; } ),
360 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
361 0.3f,
362 (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
363 (s) => { return TerrainFriction; },
364 (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
365 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
366 0.8f,
367 (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
368 (s) => { return TerrainHitFraction; },
369 (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
370 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
371 0f,
372 (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
373 (s) => { return TerrainRestitution; },
374 (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
375 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
376 0.04f,
377 (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
378 (s) => { return TerrainCollisionMargin; },
379 (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
380
381 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
382 0.2f,
383 (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); },
384 (s) => { return AvatarFriction; },
385 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
386 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
387 10.0f,
388 (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
389 (s) => { return AvatarStandingFriction; },
390 (s,p,l,v) => { AvatarStandingFriction = v; } ),
391 new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
392 1.3f,
393 (s,cf,p,v) => { AvatarAlwaysRunFactor = cf.GetFloat(p, v); },
394 (s) => { return AvatarAlwaysRunFactor; },
395 (s,p,l,v) => { AvatarAlwaysRunFactor = v; } ),
396 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
397 3.5f,
398 (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
399 (s) => { return AvatarDensity; },
400 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
401 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
402 0f,
403 (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
404 (s) => { return AvatarRestitution; },
405 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
406 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
407 0.6f,
408 (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
409 (s) => { return AvatarCapsuleWidth; },
410 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
411 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
412 0.45f,
413 (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
414 (s) => { return AvatarCapsuleDepth; },
415 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
416 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
417 1.5f,
418 (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
419 (s) => { return AvatarCapsuleHeight; },
420 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
421 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
422 0.1f,
423 (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
424 (s) => { return AvatarContactProcessingThreshold; },
425 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
426 new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction",
427 0.3f,
428 (s,cf,p,v) => { AvatarStepHeight = cf.GetFloat(p, v); },
429 (s) => { return AvatarStepHeight; },
430 (s,p,l,v) => { AvatarStepHeight = v; } ),
431 new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
432 0.6f,
433 (s,cf,p,v) => { AvatarStepApproachFactor = cf.GetFloat(p, v); },
434 (s) => { return AvatarStepApproachFactor; },
435 (s,p,l,v) => { AvatarStepApproachFactor = v; } ),
436 new ParameterDefn("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
437 2.0f,
438 (s,cf,p,v) => { AvatarStepForceFactor = cf.GetFloat(p, v); },
439 (s) => { return AvatarStepForceFactor; },
440 (s,p,l,v) => { AvatarStepForceFactor = v; } ),
441
442 new ParameterDefn("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
443 1000.0f,
444 (s,cf,p,v) => { VehicleMaxLinearVelocity = cf.GetFloat(p, v); },
445 (s) => { return (float)VehicleMaxLinearVelocity; },
446 (s,p,l,v) => { VehicleMaxLinearVelocity = v; } ),
447 new ParameterDefn("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
448 12.0f,
449 (s,cf,p,v) => { VehicleMaxAngularVelocity = cf.GetFloat(p, v); },
450 (s) => { return (float)VehicleMaxAngularVelocity; },
451 (s,p,l,v) => { VehicleMaxAngularVelocity = v; } ),
452 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
453 0.0f,
454 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
455 (s) => { return VehicleAngularDamping; },
456 (s,p,l,v) => { VehicleAngularDamping = v; } ),
457 new ParameterDefn("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
458 ConfigurationParameters.numericFalse,
459 (s,cf,p,v) => { VehicleDebuggingEnabled = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
460 (s) => { return VehicleDebuggingEnabled; },
461 (s,p,l,v) => { VehicleDebuggingEnabled = v; } ),
462
463 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
464 0f,
465 (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
466 (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
467 (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
468 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
469 0f,
470 (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
471 (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
472 (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
473 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
474 ConfigurationParameters.numericFalse,
475 (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
476 (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
477 (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
478 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
479 ConfigurationParameters.numericFalse,
480 (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
481 (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
482 (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
483 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
484 ConfigurationParameters.numericTrue,
485 (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
486 (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
487 (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
488 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
489 ConfigurationParameters.numericTrue,
490 (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
491 (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
492 (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
493 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
494 ConfigurationParameters.numericTrue,
495 (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
496 (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
497 (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
498 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
499 0f, // zero says use Bullet default
500 (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
501 (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
502 (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
503
504 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
505 (float)BSLinkset.LinksetImplementation.Compound,
506 (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
507 (s) => { return LinksetImplementation; },
508 (s,p,l,v) => { LinksetImplementation = v; } ),
509 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
510 ConfigurationParameters.numericFalse,
511 (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
512 (s) => { return LinkConstraintUseFrameOffset; },
513 (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
514 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
515 ConfigurationParameters.numericTrue,
516 (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
517 (s) => { return LinkConstraintEnableTransMotor; },
518 (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
519 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
520 5.0f,
521 (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
522 (s) => { return LinkConstraintTransMotorMaxVel; },
523 (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
524 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
525 0.1f,
526 (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
527 (s) => { return LinkConstraintTransMotorMaxForce; },
528 (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
529 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
530 0.1f,
531 (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
532 (s) => { return LinkConstraintCFM; },
533 (s,p,l,v) => { LinkConstraintCFM = v; } ),
534 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
535 0.1f,
536 (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
537 (s) => { return LinkConstraintERP; },
538 (s,p,l,v) => { LinkConstraintERP = v; } ),
539 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
540 40,
541 (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
542 (s) => { return LinkConstraintSolverIterations; },
543 (s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
544
545 new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
546 0f,
547 (s,cf,p,v) => { s.PhysicsMetricDumpFrames = cf.GetFloat(p, (int)v); },
548 (s) => { return (float)s.PhysicsMetricDumpFrames; },
549 (s,p,l,v) => { s.PhysicsMetricDumpFrames = (int)v; } ),
550 new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
551 0f,
552 (s,cf,p,v) => { ; },
553 (s) => { return 0f; },
554 (s,p,l,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ),
555 new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
556 0f,
557 (s,cf,p,v) => { ; },
558 (s) => { return 0f; },
559 (s,p,l,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
560 };
561
562 // Convert a boolean to our numeric true and false values
563 public static float NumericBool(bool b)
564 {
565 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
566 }
567
568 // Convert numeric true and false values to a boolean
569 public static bool BoolNumeric(float b)
570 {
571 return (b == ConfigurationParameters.numericTrue ? true : false);
572 }
573
574 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v)
575 {
576 BSScene physScene = pPhysScene;
577 physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate()
578 {
579 physScene.PE.ResetBroadphasePool(physScene.World);
580 });
581 }
582
583 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
584 {
585 BSScene physScene = pPhysScene;
586 physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate()
587 {
588 physScene.PE.ResetConstraintSolver(physScene.World);
589 });
590 }
591
592 // Search through the parameter definitions and return the matching
593 // ParameterDefn structure.
594 // Case does not matter as names are compared after converting to lower case.
595 // Returns 'false' if the parameter is not found.
596 internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
597 {
598 bool ret = false;
599 ParameterDefn foundDefn = new ParameterDefn();
600 string pName = paramName.ToLower();
601
602 foreach (ParameterDefn parm in ParameterDefinitions)
603 {
604 if (pName == parm.name.ToLower())
605 {
606 foundDefn = parm;
607 ret = true;
608 break;
609 }
610 }
611 defn = foundDefn;
612 return ret;
613 }
614
615 // Pass through the settable parameters and set the default values
616 internal static void SetParameterDefaultValues(BSScene physicsScene)
617 {
618 foreach (ParameterDefn parm in ParameterDefinitions)
619 {
620 parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
621 }
622 }
623
624 // Get user set values out of the ini file.
625 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
626 {
627 foreach (ParameterDefn parm in ParameterDefinitions)
628 {
629 parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
630 }
631 }
632
633 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
634
635 // This creates an array in the correct format for returning the list of
636 // parameters. This is used by the 'list' option of the 'physics' command.
637 internal static void BuildParameterTable()
638 {
639 if (SettableParameters.Length < ParameterDefinitions.Length)
640 {
641 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
642 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
643 {
644 ParameterDefn pd = ParameterDefinitions[ii];
645 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
646 }
647
648 // make the list alphabetical for estetic reasons
649 entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); });
650
651 SettableParameters = entries.ToArray();
652 }
653 }
654
655
656}
657}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..027c786 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()
@@ -57,26 +77,45 @@ public abstract class BSPhysObject : PhysicsActor
57 PhysObjectName = name; 77 PhysObjectName = name;
58 TypeName = typeName; 78 TypeName = typeName;
59 79
80 // We don't have any physical representation yet.
81 PhysBody = new BulletBody(localID);
82 PhysShape = new BulletShape();
83
84 // A linkset of just me
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 85 Linkset = BSLinkset.Factory(PhysicsScene, this);
86 PositionDisplacement = OMV.Vector3.Zero;
87
61 LastAssetBuildFailed = false; 88 LastAssetBuildFailed = false;
62 89
90 // Default material type
91 Material = MaterialAttributes.Material.Wood;
92
63 CollisionCollection = new CollisionEventUpdate(); 93 CollisionCollection = new CollisionEventUpdate();
94 CollisionsLastTick = CollisionCollection;
64 SubscribedEventsMs = 0; 95 SubscribedEventsMs = 0;
65 CollidingStep = 0; 96 CollidingStep = 0;
66 CollidingGroundStep = 0; 97 CollidingGroundStep = 0;
67 } 98 }
68 99
100 // Tell the object to clean up.
101 public virtual void Destroy()
102 {
103 UnRegisterAllPreStepActions();
104 }
105
69 public BSScene PhysicsScene { get; protected set; } 106 public BSScene PhysicsScene { get; protected set; }
70 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor 107 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
71 public string PhysObjectName { get; protected set; } 108 public string PhysObjectName { get; protected set; }
72 public string TypeName { get; protected set; } 109 public string TypeName { get; protected set; }
73 110
74 public BSLinkset Linkset { get; set; } 111 public BSLinkset Linkset { get; set; }
112 public BSLinksetInfo LinksetInfo { get; set; }
75 113
76 // Return the object mass without calculating it or having side effects 114 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 115 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...) 116 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass); 117 // 'inWorld' true if the object has already been added to the dynamic world.
118 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
80 119
81 // The last value calculated for the prim's inertia 120 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; } 121 public OMV.Vector3 Inertia { get; set; }
@@ -105,9 +144,22 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 144 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 145 public EntityProperties LastEntityProperties { get; set; }
107 146
108 public abstract OMV.Vector3 Scale { get; set; } 147 public virtual OMV.Vector3 Scale { get; set; }
109 public abstract bool IsSolid { get; } 148 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 149 public abstract bool IsStatic { get; }
150 public abstract bool IsSelected { get; }
151
152 // It can be confusing for an actor to know if it should move or update an object
153 // depeneding on the setting of 'selected', 'physical, ...
154 // This flag is the true test -- if true, the object is being acted on in the physical world
155 public abstract bool IsPhysicallyActive { get; }
156
157 // Materialness
158 public MaterialAttributes.Material Material { get; private set; }
159 public override void SetMaterial(int material)
160 {
161 Material = (MaterialAttributes.Material)material;
162 }
111 163
112 // Stop all physical motion. 164 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 165 public abstract void ZeroMotion(bool inTaintTime);
@@ -119,15 +171,41 @@ public abstract class BSPhysObject : PhysicsActor
119 // Update the physical location and motion of the object. Called with data from Bullet. 171 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop); 172 public abstract void UpdateProperties(EntityProperties entprop);
121 173
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; } 174 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; } 175 public abstract OMV.Vector3 ForcePosition { get; set; }
127 176
177 // Position is what the simulator thinks the positions of the prim is.
178 // Because Bullet needs the zero coordinate to be the center of mass of the linkset,
179 // sometimes it is necessary to displace the position the physics engine thinks
180 // the position is. PositionDisplacement must be added and removed from the
181 // position as the simulator position is stored and fetched from the physics
182 // engine.
183 public virtual OMV.Vector3 PositionDisplacement { get; set; }
184
128 public abstract OMV.Quaternion RawOrientation { get; set; } 185 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 186 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 187
188 // The system is telling us the velocity it wants to move at.
189 // Velocity in world coordinates.
190 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
191 public override OMV.Vector3 TargetVelocity
192 {
193 get { return m_targetVelocity; }
194 set
195 {
196 m_targetVelocity = value;
197 Velocity = value;
198 }
199 }
200 public virtual float TargetSpeed
201 {
202 get
203 {
204 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
205 return characterOrientedVelocity.X;
206 }
207 }
208 public abstract OMV.Vector3 RawVelocity { get; set; }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 209 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 210
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 211 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -136,6 +214,15 @@ public abstract class BSPhysObject : PhysicsActor
136 214
137 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 215 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
138 216
217 public virtual float ForwardSpeed
218 {
219 get
220 {
221 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
222 return characterOrientedVelocity.X;
223 }
224 }
225
139 #region Collisions 226 #region Collisions
140 227
141 // Requested number of milliseconds between collision events. Zero means disabled. 228 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -146,26 +233,65 @@ public abstract class BSPhysObject : PhysicsActor
146 protected long CollidingStep { get; set; } 233 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground 234 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; } 235 protected long CollidingGroundStep { get; set; }
236 // The simulation step that last collided with an object
237 protected long CollidingObjectStep { get; set; }
149 // The collision flags we think are set in Bullet 238 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; } 239 protected CollisionFlags CurrentCollisionFlags { get; set; }
151 240
241 public override bool IsColliding {
242 get { return (CollidingStep == PhysicsScene.SimulationStep); }
243 set {
244 if (value)
245 CollidingStep = PhysicsScene.SimulationStep;
246 else
247 CollidingStep = 0;
248 }
249 }
250 public override bool CollidingGround {
251 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
252 set
253 {
254 if (value)
255 CollidingGroundStep = PhysicsScene.SimulationStep;
256 else
257 CollidingGroundStep = 0;
258 }
259 }
260 public override bool CollidingObj {
261 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
262 set {
263 if (value)
264 CollidingObjectStep = PhysicsScene.SimulationStep;
265 else
266 CollidingObjectStep = 0;
267 }
268 }
269
152 // The collisions that have been collected this tick 270 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection; 271 protected CollisionEventUpdate CollisionCollection;
272 // Remember collisions from last tick for fancy collision based actions
273 // (like a BSCharacter walking up stairs).
274 protected CollisionEventUpdate CollisionsLastTick;
154 275
155 // The simulation step is telling this object about a collision. 276 // The simulation step is telling this object about a collision.
156 // Return 'true' if a collision was processed and should be sent up. 277 // Return 'true' if a collision was processed and should be sent up.
278 // 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 279 // Called at taint time from within the Step() function
158 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 280 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
159 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 281 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
160 { 282 {
161 bool ret = false; 283 bool ret = false;
162 284
163 // The following lines make IsColliding() and IsCollidingGround() work 285 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
164 CollidingStep = PhysicsScene.SimulationStep; 286 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 287 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 { 288 {
167 CollidingGroundStep = PhysicsScene.SimulationStep; 289 CollidingGroundStep = PhysicsScene.SimulationStep;
168 } 290 }
291 else
292 {
293 CollidingObjectStep = PhysicsScene.SimulationStep;
294 }
169 295
170 // prims in the same linkset cannot collide with each other 296 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) 297 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
@@ -191,8 +317,9 @@ public abstract class BSPhysObject : PhysicsActor
191 public virtual bool SendCollisions() 317 public virtual bool SendCollisions()
192 { 318 {
193 bool ret = true; 319 bool ret = true;
320
194 // If the 'no collision' call, force it to happen right now so quick collision_end 321 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 322 bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0);
196 323
197 // throttle the collisions to the number of milliseconds specified in the subscription 324 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 325 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -207,11 +334,16 @@ public abstract class BSPhysObject : PhysicsActor
207 ret = false; 334 ret = false;
208 } 335 }
209 336
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 337 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 338 base.SendCollisionUpdate(CollisionCollection);
212 339
213 // The collisionCollection structure is passed around in the simulator. 340 // Remember the collisions from this tick for some collision specific processing.
341 CollisionsLastTick = CollisionCollection;
342
343 // 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. 344 // Make sure we don't have a handle to that one and that a new one is used for next time.
345 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
346 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 347 CollisionCollection = new CollisionEventUpdate();
216 } 348 }
217 return ret; 349 return ret;
@@ -229,7 +361,8 @@ public abstract class BSPhysObject : PhysicsActor
229 361
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 362 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 363 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 364 if (PhysBody.HasPhysicalBody)
365 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 366 });
234 } 367 }
235 else 368 else
@@ -243,7 +376,9 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 376 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 377 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 378 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 379 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
380 if (PhysBody.HasPhysicalBody)
381 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 382 });
248 } 383 }
249 // Return 'true' if the simulator wants collision events 384 // Return 'true' if the simulator wants collision events
@@ -253,11 +388,66 @@ public abstract class BSPhysObject : PhysicsActor
253 388
254 #endregion // Collisions 389 #endregion // Collisions
255 390
391 #region Per Simulation Step actions
392 // There are some actions that must be performed for a physical object before each simulation step.
393 // These actions are optional so, rather than scanning all the physical objects and asking them
394 // if they have anything to do, a physical object registers for an event call before the step is performed.
395 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
396 private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
397 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
398 {
399 string identifier = op + "-" + id.ToString();
400
401 lock (RegisteredActions)
402 {
403 // Clean out any existing action
404 UnRegisterPreStepAction(op, id);
405
406 RegisteredActions[identifier] = actn;
407 }
408 PhysicsScene.BeforeStep += actn;
409 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
410 }
411
412 // Unregister a pre step action. Safe to call if the action has not been registered.
413 protected void UnRegisterPreStepAction(string op, uint id)
414 {
415 string identifier = op + "-" + id.ToString();
416 bool removed = false;
417 lock (RegisteredActions)
418 {
419 if (RegisteredActions.ContainsKey(identifier))
420 {
421 PhysicsScene.BeforeStep -= RegisteredActions[identifier];
422 RegisteredActions.Remove(identifier);
423 removed = true;
424 }
425 }
426 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
427 }
428
429 protected void UnRegisterAllPreStepActions()
430 {
431 lock (RegisteredActions)
432 {
433 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
434 {
435 PhysicsScene.BeforeStep -= kvp.Value;
436 }
437 RegisteredActions.Clear();
438 }
439 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
440 }
441
442
443 #endregion // Per Simulation Step actions
444
256 // High performance detailed logging routine used by the physical objects. 445 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args) 446 protected void DetailLog(string msg, params Object[] args)
258 { 447 {
259 if (PhysicsScene.PhysicsLogging.Enabled) 448 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args); 449 PhysicsScene.DetailLog(msg, args);
261 } 450 }
451
262} 452}
263} 453}
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..f80084a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -45,13 +45,15 @@ public sealed class BSPrim : BSPhysObject
45 private static readonly string LogHeader = "[BULLETS PRIM]"; 45 private static readonly string LogHeader = "[BULLETS PRIM]";
46 46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
50 49
51 private bool _grabbed; 50 private bool _grabbed;
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; 58 private float _density;
57 private OMV.Vector3 _force; 59 private OMV.Vector3 _force;
@@ -67,9 +69,6 @@ public sealed class BSPrim : BSPhysObject
67 private float _restitution; 69 private float _restitution;
68 private bool _setAlwaysRun; 70 private bool _setAlwaysRun;
69 private bool _throttleUpdates; 71 private bool _throttleUpdates;
70 private bool _isColliding;
71 private bool _collidingGround;
72 private bool _collidingObj;
73 private bool _floatOnWater; 72 private bool _floatOnWater;
74 private OMV.Vector3 _rotationalVelocity; 73 private OMV.Vector3 _rotationalVelocity;
75 private bool _kinematic; 74 private bool _kinematic;
@@ -77,13 +76,14 @@ public sealed class BSPrim : BSPhysObject
77 76
78 private BSDynamics _vehicle; 77 private BSDynamics _vehicle;
79 78
79 private BSVMotor _targetMotor;
80 private OMV.Vector3 _PIDTarget; 80 private OMV.Vector3 _PIDTarget;
81 private bool _usePID;
82 private float _PIDTau; 81 private float _PIDTau;
83 private bool _useHoverPID; 82
83 private BSFMotor _hoverMotor;
84 private float _PIDHoverHeight; 84 private float _PIDHoverHeight;
85 private PIDHoverType _PIDHoverType; 85 private PIDHoverType _PIDHoverType;
86 private float _PIDHoverTao; 86 private float _PIDHoverTau;
87 87
88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -93,23 +93,27 @@ public sealed class BSPrim : BSPhysObject
93 _physicsActorType = (int)ActorTypes.Prim; 93 _physicsActorType = (int)ActorTypes.Prim;
94 _position = pos; 94 _position = pos;
95 _size = size; 95 _size = size;
96 Scale = size; // the scale will be set by CreateGeom depending on object type 96 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
97 _orientation = rotation; 97 _orientation = rotation;
98 _buoyancy = 1f; 98 _buoyancy = 0f;
99 _velocity = OMV.Vector3.Zero; 99 _velocity = OMV.Vector3.Zero;
100 _rotationalVelocity = OMV.Vector3.Zero; 100 _rotationalVelocity = OMV.Vector3.Zero;
101 BaseShape = pbs; 101 BaseShape = pbs;
102 _isPhysical = pisPhysical; 102 _isPhysical = pisPhysical;
103 _isVolumeDetect = false; 103 _isVolumeDetect = false;
104 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material 104
105 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material 105 // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
106 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
107 _density = PhysicsScene.Params.defaultDensity;
108 _friction = PhysicsScene.Params.defaultFriction;
106 _restitution = PhysicsScene.Params.defaultRestitution; 109 _restitution = PhysicsScene.Params.defaultRestitution;
110
107 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness 111 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
112
108 _mass = CalculateMass(); 113 _mass = CalculateMass();
109 114
110 // No body or shape yet 115 // Cause linkset variables to be initialized (like mass)
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero); 116 Linkset.Refresh(this);
112 PhysShape = new BulletShape(IntPtr.Zero);
113 117
114 DetailLog("{0},BSPrim.constructor,call", LocalID); 118 DetailLog("{0},BSPrim.constructor,call", LocalID);
115 // do the actual object creation at taint time 119 // do the actual object creation at taint time
@@ -117,7 +121,7 @@ public sealed class BSPrim : BSPhysObject
117 { 121 {
118 CreateGeomAndObject(true); 122 CreateGeomAndObject(true);
119 123
120 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); 124 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody);
121 }); 125 });
122 } 126 }
123 127
@@ -125,10 +129,11 @@ public sealed class BSPrim : BSPhysObject
125 public override void Destroy() 129 public override void Destroy()
126 { 130 {
127 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 131 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
132 base.Destroy();
128 133
129 // Undo any links between me and any other object 134 // Undo any links between me and any other object
130 BSPhysObject parentBefore = Linkset.LinksetRoot; 135 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG DEBUG
131 int childrenBefore = Linkset.NumberOfChildren; 136 int childrenBefore = Linkset.NumberOfChildren; // DEBUG DEBUG
132 137
133 Linkset = Linkset.RemoveMeFromLinkset(this); 138 Linkset = Linkset.RemoveMeFromLinkset(this);
134 139
@@ -143,7 +148,9 @@ public sealed class BSPrim : BSPhysObject
143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 148 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
144 // If there are physical body and shape, release my use of same. 149 // If there are physical body and shape, release my use of same.
145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 150 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
151 PhysBody.Clear();
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 152 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
153 PhysShape.Clear();
147 }); 154 });
148 } 155 }
149 156
@@ -157,16 +164,15 @@ public sealed class BSPrim : BSPhysObject
157 // We presume the scale and size are the same. If scale must be changed for 164 // 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. 165 // the physical shape, that is done when the geometry is built.
159 _size = value; 166 _size = value;
167 Scale = _size;
160 ForceBodyShapeRebuild(false); 168 ForceBodyShapeRebuild(false);
161 } 169 }
162 } 170 }
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 171
167 public override PrimitiveBaseShape Shape { 172 public override PrimitiveBaseShape Shape {
168 set { 173 set {
169 BaseShape = value; 174 BaseShape = value;
175 LastAssetBuildFailed = false;
170 ForceBodyShapeRebuild(false); 176 ForceBodyShapeRebuild(false);
171 } 177 }
172 } 178 }
@@ -176,7 +182,6 @@ public sealed class BSPrim : BSPhysObject
176 182
177 public override bool ForceBodyShapeRebuild(bool inTaintTime) 183 public override bool ForceBodyShapeRebuild(bool inTaintTime)
178 { 184 {
179 LastAssetBuildFailed = false;
180 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() 185 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
181 { 186 {
182 _mass = CalculateMass(); // changing the shape changes the mass 187 _mass = CalculateMass(); // changing the shape changes the mass
@@ -189,15 +194,23 @@ public sealed class BSPrim : BSPhysObject
189 } 194 }
190 } 195 }
191 public override bool Selected { 196 public override bool Selected {
192 set { 197 set
193 _isSelected = value; 198 {
194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 199 if (value != _isSelected)
195 { 200 {
196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 201 _isSelected = value;
197 SetObjectDynamic(false); 202 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 }); 203 {
204 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
205 SetObjectDynamic(false);
206 });
207 }
199 } 208 }
200 } 209 }
210 public override bool IsSelected
211 {
212 get { return _isSelected; }
213 }
201 public override void CrossingFailure() { return; } 214 public override void CrossingFailure() { return; }
202 215
203 // link me to the specified parent 216 // link me to the specified parent
@@ -244,7 +257,8 @@ public sealed class BSPrim : BSPhysObject
244 // Zero some other properties in the physics engine 257 // Zero some other properties in the physics engine
245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 258 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
246 { 259 {
247 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 260 if (PhysBody.HasPhysicalBody)
261 PhysicsScene.PE.ClearAllForces(PhysBody);
248 }); 262 });
249 } 263 }
250 public override void ZeroAngularMotion(bool inTaintTime) 264 public override void ZeroAngularMotion(bool inTaintTime)
@@ -253,8 +267,12 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 267 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 268 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 269 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 270 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 271 if (PhysBody.HasPhysicalBody)
272 {
273 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
274 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
275 }
258 }); 276 });
259 } 277 }
260 278
@@ -271,41 +289,52 @@ public sealed class BSPrim : BSPhysObject
271 } 289 }
272 public override OMV.Vector3 Position { 290 public override OMV.Vector3 Position {
273 get { 291 get {
292 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
293 * and does not fetch this position info for children. Thus this is commented out.
274 // child prims move around based on their parent. Need to get the latest location 294 // child prims move around based on their parent. Need to get the latest location
275 if (!Linkset.IsRoot(this)) 295 if (!Linkset.IsRoot(this))
276 _position = Linkset.Position(this); 296 _position = Linkset.PositionGet(this);
297 */
277 298
278 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 299 // 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); 300 // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody) - PositionDisplacement;
280 return _position; 301 return _position;
281 } 302 }
282 set { 303 set {
283 // If the position must be forced into the physics engine, use ForcePosition. 304 // If the position must be forced into the physics engine, use ForcePosition.
305 // All positions are given in world positions.
284 if (_position == value) 306 if (_position == value)
285 { 307 {
308 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
286 return; 309 return;
287 } 310 }
288 _position = value; 311 _position = value;
289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
290 PositionSanityCheck(false); 312 PositionSanityCheck(false);
313
291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 314 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
292 { 315 {
293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 316 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 317 ForcePosition = _position;
295 ActivateIfPhysical(false); 318
319 // A linkset might need to know if a component information changed.
320 Linkset.UpdateProperties(UpdatedProperties.Position, this);
321
296 }); 322 });
297 } 323 }
298 } 324 }
325
299 public override OMV.Vector3 ForcePosition { 326 public override OMV.Vector3 ForcePosition {
300 get { 327 get {
301 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 328 _position = PhysicsScene.PE.GetPosition(PhysBody) - PositionDisplacement;
302 return _position; 329 return _position;
303 } 330 }
304 set { 331 set {
305 _position = value; 332 _position = value;
306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. 333 if (PhysBody.HasPhysicalBody)
307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 334 {
308 ActivateIfPhysical(false); 335 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
336 ActivateIfPhysical(false);
337 }
309 } 338 }
310 } 339 }
311 340
@@ -316,51 +345,56 @@ public sealed class BSPrim : BSPhysObject
316 { 345 {
317 bool ret = false; 346 bool ret = false;
318 347
319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 348 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
349 {
350 // The physical object is out of the known/simulated area.
351 // Upper levels of code will handle the transition to other areas so, for
352 // the time, we just ignore the position.
353 return ret;
354 }
355
356 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
320 OMV.Vector3 upForce = OMV.Vector3.Zero; 357 OMV.Vector3 upForce = OMV.Vector3.Zero;
321 if (Position.Z < terrainHeight) 358 if (RawPosition.Z < terrainHeight)
322 { 359 {
323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 360 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
324 float targetHeight = terrainHeight + (Size.Z / 2f); 361 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 362 // If the object is below ground it just has to be moved up because pushing will
326 upForce.Z = (terrainHeight - Position.Z) * 1f; 363 // not get it through the terrain
364 _position.Z = targetHeight;
365 if (inTaintTime)
366 ForcePosition = _position;
327 ret = true; 367 ret = true;
328 } 368 }
329 369
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 370 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 371 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 372 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 373 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 374 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
335 { 375 {
336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec. 376 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f; 377 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
378
379 // Apply upforce and overcome gravity.
380 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
381 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
382 AddForce(correctionForce, false, inTaintTime);
338 ret = true; 383 ret = true;
339 } 384 }
340 } 385 }
341 386
342 // TODO: check for out of bounds
343
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
345 if (ret)
346 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate()
348 {
349 // Apply upforce and overcome gravity.
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
351 });
352 }
353 return ret; 387 return ret;
354 } 388 }
355 389
356 // Return the effective mass of the object. 390 // Return the effective mass of the object.
357 // If there are multiple items in the linkset, add them together for the root 391 // The definition of this call is to return the mass of the prim.
392 // If the simulator cares about the mass of the linkset, it will sum it itself.
358 public override float Mass 393 public override float Mass
359 { 394 {
360 get 395 get
361 { 396 {
362 return Linkset.LinksetMass; 397 return _mass;
363 // return _mass;
364 } 398 }
365 } 399 }
366 400
@@ -370,25 +404,64 @@ public sealed class BSPrim : BSPhysObject
370 } 404 }
371 // Set the physical mass to the passed mass. 405 // Set the physical mass to the passed mass.
372 // Note that this does not change _mass! 406 // Note that this does not change _mass!
373 public override void UpdatePhysicalMassProperties(float physMass) 407 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
374 { 408 {
375 if (IsStatic) 409 if (PhysBody.HasPhysicalBody)
376 { 410 {
377 Inertia = OMV.Vector3.Zero; 411 if (IsStatic)
378 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); 412 {
379 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); 413 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity);
380 } 414 Inertia = OMV.Vector3.Zero;
381 else 415 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia);
382 { 416 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
383 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 417 }
384 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); 418 else
385 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); 419 {
386 // center of mass is at the zero of the object 420 OMV.Vector3 grav = ComputeGravity(Buoyancy);
387 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); 421
388 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia); 422 if (inWorld)
423 {
424 // Changing interesting properties doesn't change proxy and collision cache
425 // information. The Bullet solution is to re-add the object to the world
426 // after parameters are changed.
427 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
428 }
429
430 // The computation of mass props requires gravity to be set on the object.
431 PhysicsScene.PE.SetGravity(PhysBody, grav);
432
433 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
434 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
435 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
436
437 // center of mass is at the zero of the object
438 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation);
439 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld);
440
441 if (inWorld)
442 {
443 AddObjectToPhysicalWorld();
444 }
445
446 // Must set gravity after it has been added to the world because, for unknown reasons,
447 // adding the object resets the object's gravity to world gravity
448 PhysicsScene.PE.SetGravity(PhysBody, grav);
449
450 }
389 } 451 }
390 } 452 }
391 453
454 // Return what gravity should be set to this very moment
455 public OMV.Vector3 ComputeGravity(float buoyancy)
456 {
457 OMV.Vector3 ret = PhysicsScene.DefaultGravity;
458
459 if (!IsStatic)
460 ret *= (1f - buoyancy);
461
462 return ret;
463 }
464
392 // Is this used? 465 // Is this used?
393 public override OMV.Vector3 CenterOfMass 466 public override OMV.Vector3 CenterOfMass
394 { 467 {
@@ -405,11 +478,32 @@ public sealed class BSPrim : BSPhysObject
405 get { return _force; } 478 get { return _force; }
406 set { 479 set {
407 _force = value; 480 _force = value;
408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 481 if (_force != OMV.Vector3.Zero)
409 { 482 {
410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 483 // If the force is non-zero, it must be reapplied each tick because
411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 484 // Bullet clears the forces applied last frame.
412 }); 485 RegisterPreStepAction("BSPrim.setForce", LocalID,
486 delegate(float timeStep)
487 {
488 if (!IsPhysicallyActive)
489 {
490 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
491 return;
492 }
493
494 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
495 if (PhysBody.HasPhysicalBody)
496 {
497 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
498 ActivateIfPhysical(false);
499 }
500 }
501 );
502 }
503 else
504 {
505 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
506 }
413 } 507 }
414 } 508 }
415 509
@@ -420,15 +514,18 @@ public sealed class BSPrim : BSPhysObject
420 set { 514 set {
421 Vehicle type = (Vehicle)value; 515 Vehicle type = (Vehicle)value;
422 516
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() 517 PhysicsScene.TaintedObject("setVehicleType", delegate()
427 { 518 {
428 // Done at taint time so we're sure the physics engine is not using the variables 519 // 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. 520 // Vehicle code changes the parameters for this vehicle type.
430 _vehicle.ProcessTypeChange(type); 521 _vehicle.ProcessTypeChange(type);
431 ActivateIfPhysical(false); 522 ActivateIfPhysical(false);
523
524 // If an active vehicle, register the vehicle code to be called before each step
525 if (_vehicle.Type == Vehicle.TYPE_NONE)
526 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
527 else
528 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
432 }); 529 });
433 } 530 }
434 } 531 }
@@ -464,23 +561,6 @@ public sealed class BSPrim : BSPhysObject
464 }); 561 });
465 } 562 }
466 563
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 564 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
485 public override void SetVolumeDetect(int param) { 565 public override void SetVolumeDetect(int param) {
486 bool newValue = (param != 0); 566 bool newValue = (param != 0);
@@ -495,6 +575,11 @@ public sealed class BSPrim : BSPhysObject
495 } 575 }
496 return; 576 return;
497 } 577 }
578 public override OMV.Vector3 RawVelocity
579 {
580 get { return _velocity; }
581 set { _velocity = value; }
582 }
498 public override OMV.Vector3 Velocity { 583 public override OMV.Vector3 Velocity {
499 get { return _velocity; } 584 get { return _velocity; }
500 set { 585 set {
@@ -502,22 +587,50 @@ public sealed class BSPrim : BSPhysObject
502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 587 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
503 { 588 {
504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 589 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 590 ForceVelocity = _velocity;
506 }); 591 });
507 } 592 }
508 } 593 }
509 public override OMV.Vector3 ForceVelocity { 594 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 595 get { return _velocity; }
511 set { 596 set {
597 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
598
512 _velocity = value; 599 _velocity = value;
513 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 600 if (PhysBody.HasPhysicalBody)
601 {
602 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity);
603 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
604 ActivateIfPhysical(false);
605 }
514 } 606 }
515 } 607 }
516 public override OMV.Vector3 Torque { 608 public override OMV.Vector3 Torque {
517 get { return _torque; } 609 get { return _torque; }
518 set { 610 set {
519 _torque = value; 611 _torque = value;
520 AddAngularForce(_torque, false, false); 612 if (_torque != OMV.Vector3.Zero)
613 {
614 // If the torque is non-zero, it must be reapplied each tick because
615 // Bullet clears the forces applied last frame.
616 RegisterPreStepAction("BSPrim.setTorque", LocalID,
617 delegate(float timeStep)
618 {
619 if (!IsPhysicallyActive)
620 {
621 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
622 return;
623 }
624
625 if (PhysBody.HasPhysicalBody)
626 AddAngularForce(_torque, false, true);
627 }
628 );
629 }
630 else
631 {
632 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
633 }
521 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 634 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
522 } 635 }
523 } 636 }
@@ -537,23 +650,28 @@ public sealed class BSPrim : BSPhysObject
537 } 650 }
538 public override OMV.Quaternion Orientation { 651 public override OMV.Quaternion Orientation {
539 get { 652 get {
653 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
654 * and does not fetch this position info for children. Thus this is commented out.
540 // Children move around because tied to parent. Get a fresh value. 655 // Children move around because tied to parent. Get a fresh value.
541 if (!Linkset.IsRoot(this)) 656 if (!Linkset.IsRoot(this))
542 { 657 {
543 _orientation = Linkset.Orientation(this); 658 _orientation = Linkset.OrientationGet(this);
544 } 659 }
660 */
545 return _orientation; 661 return _orientation;
546 } 662 }
547 set { 663 set {
548 if (_orientation == value) 664 if (_orientation == value)
549 return; 665 return;
550 _orientation = value; 666 _orientation = value;
551 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 667
552 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 668 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
553 { 669 {
554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 670 ForceOrientation = _orientation;
555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 671
556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 672 // A linkset might need to know if a component information changed.
673 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
674
557 }); 675 });
558 } 676 }
559 } 677 }
@@ -562,13 +680,14 @@ public sealed class BSPrim : BSPhysObject
562 { 680 {
563 get 681 get
564 { 682 {
565 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 683 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
566 return _orientation; 684 return _orientation;
567 } 685 }
568 set 686 set
569 { 687 {
570 _orientation = value; 688 _orientation = value;
571 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 689 if (PhysBody.HasPhysicalBody)
690 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
572 } 691 }
573 } 692 }
574 public override int PhysicsActorType { 693 public override int PhysicsActorType {
@@ -583,7 +702,7 @@ public sealed class BSPrim : BSPhysObject
583 _isPhysical = value; 702 _isPhysical = value;
584 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 703 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
585 { 704 {
586 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 705 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
587 SetObjectDynamic(true); 706 SetObjectDynamic(true);
588 // whether phys-to-static or static-to-phys, the object is not moving. 707 // whether phys-to-static or static-to-phys, the object is not moving.
589 ZeroMotion(true); 708 ZeroMotion(true);
@@ -604,6 +723,12 @@ public sealed class BSPrim : BSPhysObject
604 get { return !IsPhantom && !_isVolumeDetect; } 723 get { return !IsPhantom && !_isVolumeDetect; }
605 } 724 }
606 725
726 // The object is moving and is actively being dynamic in the physical world
727 public override bool IsPhysicallyActive
728 {
729 get { return !_isSelected && IsPhysical; }
730 }
731
607 // Make gravity work if the object is physical and not selected 732 // Make gravity work if the object is physical and not selected
608 // Called at taint-time!! 733 // Called at taint-time!!
609 private void SetObjectDynamic(bool forceRebuild) 734 private void SetObjectDynamic(bool forceRebuild)
@@ -624,7 +749,7 @@ public sealed class BSPrim : BSPhysObject
624 749
625 // Mangling all the physical properties requires the object not be in the physical world. 750 // 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). 751 // 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); 752 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
628 753
629 // Set up the object physicalness (does gravity and collisions move this object) 754 // Set up the object physicalness (does gravity and collisions move this object)
630 MakeDynamic(IsStatic); 755 MakeDynamic(IsStatic);
@@ -638,16 +763,10 @@ public sealed class BSPrim : BSPhysObject
638 // Make solid or not (do things bounce off or pass through this object). 763 // Make solid or not (do things bounce off or pass through this object).
639 MakeSolid(IsSolid); 764 MakeSolid(IsSolid);
640 765
641 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 766 AddObjectToPhysicalWorld();
642 767
643 // Rebuild its shape 768 // Rebuild its shape
644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 769 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 770
652 // Recompute any linkset parameters. 771 // Recompute any linkset parameters.
653 // When going from non-physical to physical, this re-enables the constraints that 772 // When going from non-physical to physical, this re-enables the constraints that
@@ -655,8 +774,8 @@ public sealed class BSPrim : BSPhysObject
655 // For compound based linksets, this enables and disables interactions of the children. 774 // For compound based linksets, this enables and disables interactions of the children.
656 Linkset.Refresh(this); 775 Linkset.Refresh(this);
657 776
658 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 777 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); 778 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
660 } 779 }
661 780
662 // "Making dynamic" means changing to and from static. 781 // "Making dynamic" means changing to and from static.
@@ -669,74 +788,80 @@ public sealed class BSPrim : BSPhysObject
669 if (makeStatic) 788 if (makeStatic)
670 { 789 {
671 // Become a Bullet 'static' object type 790 // Become a Bullet 'static' object type
672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 791 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
673 // Stop all movement 792 // Stop all movement
674 ZeroMotion(true); 793 ZeroMotion(true);
675 // Center of mass is at the center of the object 794
676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 795 // Set various physical properties so other object interact properly
796 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
797 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
798 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
799
677 // Mass is zero which disables a bunch of physics stuff in Bullet 800 // Mass is zero which disables a bunch of physics stuff in Bullet
678 UpdatePhysicalMassProperties(0f); 801 UpdatePhysicalMassProperties(0f, false);
679 // Set collision detection parameters 802 // Set collision detection parameters
680 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 803 if (BSParam.CcdMotionThreshold > 0f)
681 { 804 {
682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 805 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 806 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
684 } 807 }
685 // There can be special things needed for implementing linksets 808
686 Linkset.MakeStatic(this);
687 // The activation state is 'disabled' so Bullet will not try to act on it. 809 // The activation state is 'disabled' so Bullet will not try to act on it.
688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 810 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
689 // Start it out sleeping and physical actions could wake it up. 811 // Start it out sleeping and physical actions could wake it up.
690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 812 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
813
814 // This collides like a static object
815 PhysBody.collisionType = CollisionType.Static;
691 816
692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 817 // There can be special things needed for implementing linksets
693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 818 Linkset.MakeStatic(this);
694 } 819 }
695 else 820 else
696 { 821 {
697 // Not a Bullet static object 822 // Not a Bullet static object
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 823 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
699 824
700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 825 // Set various physical properties so other object interact properly
701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 826 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 827 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
828 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
703 829
704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 830 // 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 831 // Since this can be called multiple times, only zero forces when becoming physical
706 // BulletSimAPI.ClearAllForces2(BSBody.ptr); 832 // PhysicsScene.PE.ClearAllForces(BSBody);
707 833
708 // For good measure, make sure the transform is set through to the motion state 834 // For good measure, make sure the transform is set through to the motion state
709 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 835 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
710 836
711 // Center of mass is at the center of the object 837 // Center of mass is at the center of the object
712 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 838 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation);
713 839
714 // A dynamic object has mass 840 // A dynamic object has mass
715 UpdatePhysicalMassProperties(RawMass); 841 UpdatePhysicalMassProperties(RawMass, false);
716 842
717 // Set collision detection parameters 843 // Set collision detection parameters
718 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 844 if (BSParam.CcdMotionThreshold > 0f)
719 { 845 {
720 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 846 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
721 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 847 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
722 } 848 }
723 849
724 // Various values for simulation limits 850 // Various values for simulation limits
725 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 851 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
726 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); 852 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 853 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 854 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
729 855
730 // There might be special things needed for implementing linksets. 856 // This collides like an object.
731 Linkset.MakeDynamic(this); 857 PhysBody.collisionType = CollisionType.Dynamic;
732 858
733 // Force activation of the object so Bullet will act on it. 859 // Force activation of the object so Bullet will act on it.
734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 860 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 861 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
736 // BulletSimAPI.Activate2(BSBody.ptr, true);
737 862
738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 863 // There might be special things needed for implementing linksets.
739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; 864 Linkset.MakeDynamic(this);
740 } 865 }
741 } 866 }
742 867
@@ -746,7 +871,7 @@ public sealed class BSPrim : BSPhysObject
746 // the functions after this one set up the state of a possibly newly created collision body. 871 // the functions after this one set up the state of a possibly newly created collision body.
747 private void MakeSolid(bool makeSolid) 872 private void MakeSolid(bool makeSolid)
748 { 873 {
749 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); 874 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody);
750 if (makeSolid) 875 if (makeSolid)
751 { 876 {
752 // Verify the previous code created the correct shape for this type of thing. 877 // Verify the previous code created the correct shape for this type of thing.
@@ -754,7 +879,7 @@ public sealed class BSPrim : BSPhysObject
754 { 879 {
755 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 880 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
756 } 881 }
757 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 882 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
758 } 883 }
759 else 884 else
760 { 885 {
@@ -762,9 +887,10 @@ public sealed class BSPrim : BSPhysObject
762 { 887 {
763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 888 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
764 } 889 }
765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 890 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 891
767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 892 // Change collision info from a static object to a ghosty collision object
893 PhysBody.collisionType = CollisionType.VolumeDetect;
768 } 894 }
769 } 895 }
770 896
@@ -773,8 +899,8 @@ public sealed class BSPrim : BSPhysObject
773 // Called in taint-time!! 899 // Called in taint-time!!
774 private void ActivateIfPhysical(bool forceIt) 900 private void ActivateIfPhysical(bool forceIt)
775 { 901 {
776 if (IsPhysical) 902 if (IsPhysical && PhysBody.HasPhysicalBody)
777 BulletSimAPI.Activate2(PhysBody.ptr, forceIt); 903 PhysicsScene.PE.Activate(PhysBody, forceIt);
778 } 904 }
779 905
780 // Turn on or off the flag controlling whether collision events are returned to the simulator. 906 // Turn on or off the flag controlling whether collision events are returned to the simulator.
@@ -782,11 +908,27 @@ public sealed class BSPrim : BSPhysObject
782 { 908 {
783 if (wantsCollisionEvents) 909 if (wantsCollisionEvents)
784 { 910 {
785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 911 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
786 } 912 }
787 else 913 else
788 { 914 {
789 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 915 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
916 }
917 }
918
919 // Add me to the physical world.
920 // Object MUST NOT already be in the world.
921 // This routine exists because some assorted properties get mangled by adding to the world.
922 internal void AddObjectToPhysicalWorld()
923 {
924 if (PhysBody.HasPhysicalBody)
925 {
926 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
927 }
928 else
929 {
930 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
931 DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
790 } 932 }
791 } 933 }
792 934
@@ -805,18 +947,6 @@ public sealed class BSPrim : BSPhysObject
805 get { return _throttleUpdates; } 947 get { return _throttleUpdates; }
806 set { _throttleUpdates = value; } 948 set { _throttleUpdates = value; }
807 } 949 }
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 { 950 public bool IsPhantom {
821 get { 951 get {
822 // SceneObjectPart removes phantom objects from the physics scene 952 // SceneObjectPart removes phantom objects from the physics scene
@@ -831,32 +961,23 @@ public sealed class BSPrim : BSPhysObject
831 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 961 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
832 { 962 {
833 if (_floatOnWater) 963 if (_floatOnWater)
834 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 964 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
835 else 965 else
836 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 966 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
837 }); 967 });
838 } 968 }
839 } 969 }
840 public override OMV.Vector3 RotationalVelocity { 970 public override OMV.Vector3 RotationalVelocity {
841 get { 971 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; 972 return _rotationalVelocity;
852 } 973 }
853 set { 974 set {
854 _rotationalVelocity = value; 975 _rotationalVelocity = value;
976 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
855 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 977 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 978 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
857 { 979 {
858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 980 ForceRotationalVelocity = _rotationalVelocity;
859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
860 }); 981 });
861 } 982 }
862 } 983 }
@@ -866,7 +987,13 @@ public sealed class BSPrim : BSPhysObject
866 } 987 }
867 set { 988 set {
868 _rotationalVelocity = value; 989 _rotationalVelocity = value;
869 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 990 if (PhysBody.HasPhysicalBody)
991 {
992 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
993 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
994 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
995 ActivateIfPhysical(false);
996 }
870 } 997 }
871 } 998 }
872 public override bool Kinematic { 999 public override bool Kinematic {
@@ -890,9 +1017,10 @@ public sealed class BSPrim : BSPhysObject
890 set { 1017 set {
891 _buoyancy = value; 1018 _buoyancy = value;
892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 1019 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
893 // Buoyancy is faked by changing the gravity applied to the object 1020 // Force the recalculation of the various inertia,etc variables in the object
894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 1021 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass);
895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 1022 UpdatePhysicalMassProperties(_mass, true);
1023 ActivateIfPhysical(false);
896 } 1024 }
897 } 1025 }
898 1026
@@ -900,17 +1028,112 @@ public sealed class BSPrim : BSPhysObject
900 public override OMV.Vector3 PIDTarget { 1028 public override OMV.Vector3 PIDTarget {
901 set { _PIDTarget = value; } 1029 set { _PIDTarget = value; }
902 } 1030 }
903 public override bool PIDActive {
904 set { _usePID = value; }
905 }
906 public override float PIDTau { 1031 public override float PIDTau {
907 set { _PIDTau = value; } 1032 set { _PIDTau = value; }
908 } 1033 }
1034 public override bool PIDActive {
1035 set {
1036 if (value)
1037 {
1038 // We're taking over after this.
1039 ZeroMotion(true);
1040
1041 _targetMotor = new BSVMotor("BSPrim.PIDTarget",
1042 _PIDTau, // timeScale
1043 BSMotor.Infinite, // decay time scale
1044 BSMotor.InfiniteVector, // friction timescale
1045 1f // efficiency
1046 );
1047 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1048 _targetMotor.SetTarget(_PIDTarget);
1049 _targetMotor.SetCurrent(RawPosition);
1050 /*
1051 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1052 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1053
1054 _targetMotor.SetTarget(_PIDTarget);
1055 _targetMotor.SetCurrent(RawPosition);
1056 _targetMotor.TimeScale = _PIDTau;
1057 _targetMotor.Efficiency = 1f;
1058 */
1059
1060 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1061 {
1062 if (!IsPhysicallyActive)
1063 {
1064 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1065 return;
1066 }
1067
1068 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1069
1070 // 'movePosition' is where we'd like the prim to be at this moment.
1071 OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
1072
1073 // If we are very close to our target, turn off the movement motor.
1074 if (_targetMotor.ErrorIsZero())
1075 {
1076 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
1077 LocalID, movePosition, RawPosition, Mass);
1078 ForcePosition = _targetMotor.TargetValue;
1079 _targetMotor.Enabled = false;
1080 }
1081 else
1082 {
1083 ForcePosition = movePosition;
1084 }
1085 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1086 });
1087 }
1088 else
1089 {
1090 // Stop any targetting
1091 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1092 }
1093 }
1094 }
909 1095
910 // Used for llSetHoverHeight and maybe vehicle height 1096 // Used for llSetHoverHeight and maybe vehicle height
911 // Hover Height will override MoveTo target's Z 1097 // Hover Height will override MoveTo target's Z
912 public override bool PIDHoverActive { 1098 public override bool PIDHoverActive {
913 set { _useHoverPID = value; } 1099 set {
1100 if (value)
1101 {
1102 // Turning the target on
1103 _hoverMotor = new BSFMotor("BSPrim.Hover",
1104 _PIDHoverTau, // timeScale
1105 BSMotor.Infinite, // decay time scale
1106 BSMotor.Infinite, // friction timescale
1107 1f // efficiency
1108 );
1109 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1110 _hoverMotor.SetCurrent(RawPosition.Z);
1111 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1112
1113 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1114 {
1115 if (!IsPhysicallyActive)
1116 return;
1117
1118 _hoverMotor.SetCurrent(RawPosition.Z);
1119 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1120 float targetHeight = _hoverMotor.Step(timeStep);
1121
1122 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1123 // Compute the amount of force to push us there.
1124 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1125 // Undo anything the object thinks it's doing at the moment
1126 moveForce = -RawVelocity.Z * Mass;
1127
1128 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1129 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1130 });
1131 }
1132 else
1133 {
1134 UnRegisterPreStepAction("BSPrim.Hover", LocalID);
1135 }
1136 }
914 } 1137 }
915 public override float PIDHoverHeight { 1138 public override float PIDHoverHeight {
916 set { _PIDHoverHeight = value; } 1139 set { _PIDHoverHeight = value; }
@@ -919,63 +1142,109 @@ public sealed class BSPrim : BSPhysObject
919 set { _PIDHoverType = value; } 1142 set { _PIDHoverType = value; }
920 } 1143 }
921 public override float PIDHoverTau { 1144 public override float PIDHoverTau {
922 set { _PIDHoverTao = value; } 1145 set { _PIDHoverTau = value; }
1146 }
1147 // Based on current position, determine what we should be hovering at now.
1148 // Must recompute often. What if we walked offa cliff>
1149 private float ComputeCurrentPIDHoverHeight()
1150 {
1151 float ret = _PIDHoverHeight;
1152 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1153
1154 switch (_PIDHoverType)
1155 {
1156 case PIDHoverType.Ground:
1157 ret = groundHeight + _PIDHoverHeight;
1158 break;
1159 case PIDHoverType.GroundAndWater:
1160 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1161 if (groundHeight > waterHeight)
1162 {
1163 ret = groundHeight + _PIDHoverHeight;
1164 }
1165 else
1166 {
1167 ret = waterHeight + _PIDHoverHeight;
1168 }
1169 break;
1170 }
1171 return ret;
923 } 1172 }
924 1173
1174
925 // For RotLookAt 1175 // For RotLookAt
926 public override OMV.Quaternion APIDTarget { set { return; } } 1176 public override OMV.Quaternion APIDTarget { set { return; } }
927 public override bool APIDActive { set { return; } } 1177 public override bool APIDActive { set { return; } }
928 public override float APIDStrength { set { return; } } 1178 public override float APIDStrength { set { return; } }
929 public override float APIDDamping { set { return; } } 1179 public override float APIDDamping { set { return; } }
930 1180
931 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
932 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1181 public override void AddForce(OMV.Vector3 force, bool pushforce) {
933 AddForce(force, pushforce, false); 1182 // Per documentation, max force is limited.
1183 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1184
1185 // Since this force is being applied in only one step, make this a force per second.
1186 addForce /= PhysicsScene.LastTimeStep;
1187 AddForce(addForce, pushforce, false /* inTaintTime */);
934 } 1188 }
1189
935 // Applying a force just adds this to the total force on the object. 1190 // Applying a force just adds this to the total force on the object.
1191 // This added force will only last the next simulation tick.
936 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1192 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
937 // for an object, doesn't matter if force is a pushforce or not 1193 // for an object, doesn't matter if force is a pushforce or not
938 if (force.IsFinite()) 1194 if (IsPhysicallyActive)
939 { 1195 {
940 // _force += force; 1196 if (force.IsFinite())
941 lock (m_accumulatedForces)
942 m_accumulatedForces.Add(new OMV.Vector3(force));
943 }
944 else
945 {
946 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
947 return;
948 }
949 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
950 {
951 OMV.Vector3 fSum = OMV.Vector3.Zero;
952 lock (m_accumulatedForces)
953 { 1197 {
954 // Sum the accumulated additional forces for one big force to apply once. 1198 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
955 foreach (OMV.Vector3 v in m_accumulatedForces) 1199
1200 OMV.Vector3 addForce = force;
1201 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
956 { 1202 {
957 fSum += v; 1203 // Bullet adds this central force to the total force for this tick
958 } 1204 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
959 m_accumulatedForces.Clear(); 1205 if (PhysBody.HasPhysicalBody)
1206 {
1207 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
1208 ActivateIfPhysical(false);
1209 }
1210 });
960 } 1211 }
961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); 1212 else
962 if (fSum != OMV.Vector3.Zero) 1213 {
963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); 1214 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
964 }); 1215 return;
1216 }
1217 }
965 } 1218 }
966 1219
967 // An impulse force is scaled by the mass of the object. 1220 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
968 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) 1221 // for an object, doesn't matter if force is a pushforce or not
969 { 1222 if (!IsPhysicallyActive)
970 OMV.Vector3 applyImpulse = impulse;
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 { 1223 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); 1224 if (impulse.IsFinite())
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); 1225 {
975 }); 1226 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1227 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1228
1229 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate()
1230 {
1231 // Bullet adds this impulse immediately to the velocity
1232 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1233 if (PhysBody.HasPhysicalBody)
1234 {
1235 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1236 ActivateIfPhysical(false);
1237 }
1238 });
1239 }
1240 else
1241 {
1242 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1243 return;
1244 }
1245 }
976 } 1246 }
977 1247
978 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
979 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1248 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
980 AddAngularForce(force, pushforce, false); 1249 AddAngularForce(force, pushforce, false);
981 } 1250 }
@@ -983,42 +1252,37 @@ public sealed class BSPrim : BSPhysObject
983 { 1252 {
984 if (force.IsFinite()) 1253 if (force.IsFinite())
985 { 1254 {
986 // _force += force; 1255 OMV.Vector3 angForce = force;
987 lock (m_accumulatedAngularForces) 1256 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
988 m_accumulatedAngularForces.Add(new OMV.Vector3(force)); 1257 {
1258 if (PhysBody.HasPhysicalBody)
1259 {
1260 PhysicsScene.PE.ApplyTorque(PhysBody, angForce);
1261 ActivateIfPhysical(false);
1262 }
1263 });
989 } 1264 }
990 else 1265 else
991 { 1266 {
992 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1267 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
993 return; 1268 return;
994 } 1269 }
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 } 1270 }
1271
1015 // A torque impulse. 1272 // A torque impulse.
1273 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1274 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1275 // Computed as: angularVelocity += impulse * inertia;
1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1276 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 { 1277 {
1018 OMV.Vector3 applyImpulse = impulse; 1278 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1279 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 { 1280 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); 1281 if (PhysBody.HasPhysicalBody)
1282 {
1283 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1284 ActivateIfPhysical(false);
1285 }
1022 }); 1286 });
1023 } 1287 }
1024 1288
@@ -1313,11 +1577,7 @@ public sealed class BSPrim : BSPhysObject
1313 } 1577 }
1314 */ 1578 */
1315 1579
1316 if (returnMass <= 0) 1580 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1317 returnMass = 0.0001f;
1318
1319 if (returnMass > PhysicsScene.MaximumObjectMass)
1320 returnMass = PhysicsScene.MaximumObjectMass;
1321 1581
1322 return returnMass; 1582 return returnMass;
1323 }// end CalculateMass 1583 }// end CalculateMass
@@ -1326,37 +1586,20 @@ public sealed class BSPrim : BSPhysObject
1326 // Rebuild the geometry and object. 1586 // Rebuild the geometry and object.
1327 // This is called when the shape changes so we need to recreate the mesh/hull. 1587 // This is called when the shape changes so we need to recreate the mesh/hull.
1328 // Called at taint-time!!! 1588 // Called at taint-time!!!
1329 private void CreateGeomAndObject(bool forceRebuild) 1589 public void CreateGeomAndObject(bool forceRebuild)
1330 { 1590 {
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. 1591 // Create the correct physical representation for this type of object.
1337 // Updates PhysBody and PhysShape with the new information. 1592 // Updates PhysBody and PhysShape with the new information.
1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1593 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1339 // Returns 'true' if either the body or the shape was changed.
1340 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1594 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1341 { 1595 {
1342 // Called if the current prim body is about to be destroyed. 1596 // Called if the current prim body is about to be destroyed.
1343 // Remove all the physical dependencies on the old body. 1597 // Remove all the physical dependencies on the old body.
1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 1598 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1599 Linkset.RemoveBodyDependencies(this);
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); 1600 _vehicle.RemoveBodyDependencies(this);
1347 }); 1601 });
1348 1602
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 1603 // Make sure the properties are set on the new object
1361 UpdatePhysicalParameters(); 1604 UpdatePhysicalParameters();
1362 return; 1605 return;
@@ -1364,95 +1607,51 @@ public sealed class BSPrim : BSPhysObject
1364 1607
1365 // The physics engine says that properties have updated. Update same and inform 1608 // The physics engine says that properties have updated. Update same and inform
1366 // the world that things have changed. 1609 // the world that things have changed.
1367 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1368 enum UpdatedProperties {
1369 Position = 1 << 0,
1370 Rotation = 1 << 1,
1371 Velocity = 1 << 2,
1372 Acceleration = 1 << 3,
1373 RotationalVel = 1 << 4
1374 }
1375
1376 const float ROTATION_TOLERANCE = 0.01f;
1377 const float VELOCITY_TOLERANCE = 0.001f;
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) 1610 public override void UpdateProperties(EntityProperties entprop)
1383 { 1611 {
1384 /* 1612 // Updates only for individual prims and for the root object of a linkset.
1385 UpdatedProperties changed = 0; 1613 if (Linkset.IsRoot(this))
1386 // assign to the local variables so the normal set action does not happen
1387 // if (_position != entprop.Position)
1388 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1389 {
1390 _position = entprop.Position;
1391 changed |= UpdatedProperties.Position;
1392 }
1393 // if (_orientation != entprop.Rotation)
1394 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1395 {
1396 _orientation = entprop.Rotation;
1397 changed |= UpdatedProperties.Rotation;
1398 }
1399 // if (_velocity != entprop.Velocity)
1400 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1401 {
1402 _velocity = entprop.Velocity;
1403 changed |= UpdatedProperties.Velocity;
1404 }
1405 // if (_acceleration != entprop.Acceleration)
1406 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1407 {
1408 _acceleration = entprop.Acceleration;
1409 changed |= UpdatedProperties.Acceleration;
1410 }
1411 // if (_rotationalVelocity != entprop.RotationalVelocity)
1412 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1413 {
1414 _rotationalVelocity = entprop.RotationalVelocity;
1415 changed |= UpdatedProperties.RotationalVel;
1416 }
1417 if (changed != 0)
1418 { 1614 {
1419 // Only update the position of single objects and linkset roots 1615 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1420 if (Linkset.IsRoot(this)) 1616 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1617 if (_vehicle.IsActive)
1421 { 1618 {
1422 base.RequestPhysicsterseUpdate(); 1619 // entprop.RotationalVelocity = OMV.Vector3.Zero;
1423 } 1620 }
1424 }
1425 */
1426 1621
1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1622 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1428 1623
1429 // Updates only for individual prims and for the root object of a linkset. 1624 // Undo any center-of-mass displacement that might have been done.
1430 if (Linkset.IsRoot(this)) 1625 if (PositionDisplacement != OMV.Vector3.Zero)
1431 { 1626 {
1432 // Assign directly to the local variables so the normal set action does not happen 1627 // Correct for any rotation around the center-of-mass
1628 // TODO!!!
1629 entprop.Position -= PositionDisplacement;
1630 }
1631
1632 // Assign directly to the local variables so the normal set actions do not happen
1433 _position = entprop.Position; 1633 _position = entprop.Position;
1434 _orientation = entprop.Rotation; 1634 _orientation = entprop.Rotation;
1435 _velocity = entprop.Velocity; 1635 _velocity = entprop.Velocity;
1436 _acceleration = entprop.Acceleration; 1636 _acceleration = entprop.Acceleration;
1437 _rotationalVelocity = entprop.RotationalVelocity; 1637 _rotationalVelocity = entprop.RotationalVelocity;
1438 1638
1639 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1640
1439 // The sanity check can change the velocity and/or position. 1641 // The sanity check can change the velocity and/or position.
1440 if (PositionSanityCheck(true)) 1642 if (IsPhysical && PositionSanityCheck(true))
1441 { 1643 {
1442 entprop.Position = _position; 1644 entprop.Position = _position;
1443 entprop.Velocity = _velocity; 1645 entprop.Velocity = _velocity;
1444 } 1646 }
1445 1647
1648 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1649 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1650
1446 // remember the current and last set values 1651 // remember the current and last set values
1447 LastEntityProperties = CurrentEntityProperties; 1652 LastEntityProperties = CurrentEntityProperties;
1448 CurrentEntityProperties = entprop; 1653 CurrentEntityProperties = entprop;
1449 1654
1450 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1451 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1453
1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1455
1456 base.RequestPhysicsterseUpdate(); 1655 base.RequestPhysicsterseUpdate();
1457 } 1656 }
1458 /* 1657 /*
@@ -1466,7 +1665,7 @@ public sealed class BSPrim : BSPhysObject
1466 */ 1665 */
1467 1666
1468 // The linkset implimentation might want to know about this. 1667 // The linkset implimentation might want to know about this.
1469 Linkset.UpdateProperties(this); 1668 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
1470 } 1669 }
1471} 1670}
1472} 1671}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1..35dba9b 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection;
29using System.Runtime.InteropServices; 30using System.Runtime.InteropServices;
30using System.Text; 31using System.Text;
31using System.Threading; 32using System.Threading;
@@ -38,40 +39,22 @@ using Nini.Config;
38using log4net; 39using log4net;
39using OpenMetaverse; 40using OpenMetaverse;
40 41
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Test sculpties (verified that they don't work)
43// Compute physics FPS reasonably
44// Based on material, set density and friction
45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
48// At the moment, physical and phantom causes object to drop through the terrain
49// Physical phantom objects and related typing (collision options )
50// Check out llVolumeDetect. Must do something for that.
51// Use collision masks for collision with terrain and phantom objects
52// More efficient memory usage when passing hull information from BSPrim to BulletSim
53// Should prim.link() and prim.delink() membership checking happen at taint time?
54// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
55// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
56// Implement LockAngularMotion
57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
58// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
59// Add PID movement operations. What does ScenePresence.MoveToTarget do?
60// Check terrain size. 128 or 127?
61// Raycast
62//
63namespace OpenSim.Region.Physics.BulletSPlugin 42namespace OpenSim.Region.Physics.BulletSPlugin
64{ 43{
65public sealed class BSScene : PhysicsScene, IPhysicsParameters 44public sealed class BSScene : PhysicsScene, IPhysicsParameters
66{ 45{
67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 46 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
68 private static readonly string LogHeader = "[BULLETS SCENE]"; 47 internal static readonly string LogHeader = "[BULLETS SCENE]";
69 48
70 // The name of the region we're working for. 49 // The name of the region we're working for.
71 public string RegionName { get; private set; } 50 public string RegionName { get; private set; }
72 51
73 public string BulletSimVersion = "?"; 52 public string BulletSimVersion = "?";
74 53
54 // The handle to the underlying managed or unmanaged version of Bullet being used.
55 public string BulletEngineName { get; private set; }
56 public BSAPITemplate PE;
57
75 public Dictionary<uint, BSPhysObject> PhysObjects; 58 public Dictionary<uint, BSPhysObject> PhysObjects;
76 public BSShapeCollection Shapes; 59 public BSShapeCollection Shapes;
77 60
@@ -82,32 +65,29 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
82 // every tick so OpenSim will update its animation. 65 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); 66 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
84 67
85 // List of all the objects that have vehicle properties and should be called
86 // to update each physics step.
87 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
88
89 // let my minuions use my logger 68 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } } 69 public ILog Logger { get { return m_log; } }
91 70
92 public IMesher mesher; 71 public IMesher mesher;
93 // Level of Detail values kept as float because that's what the Meshmerizer wants
94 public float MeshLOD { get; private set; }
95 public float MeshMegaPrimLOD { get; private set; }
96 public float MeshMegaPrimThreshold { get; private set; }
97 public float SculptLOD { get; private set; }
98
99 public uint WorldID { get; private set; } 72 public uint WorldID { get; private set; }
100 public BulletSim World { get; private set; } 73 public BulletWorld World { get; private set; }
101 74
102 // All the constraints that have been allocated in this instance. 75 // All the constraints that have been allocated in this instance.
103 public BSConstraintCollection Constraints { get; private set; } 76 public BSConstraintCollection Constraints { get; private set; }
104 77
105 // Simulation parameters 78 // Simulation parameters
106 private int m_maxSubSteps; 79 internal int m_maxSubSteps;
107 private float m_fixedTimeStep; 80 internal float m_fixedTimeStep;
108 private long m_simulationStep = 0; 81 internal long m_simulationStep = 0;
82 internal float NominalFrameRate { get; set; }
109 public long SimulationStep { get { return m_simulationStep; } } 83 public long SimulationStep { get { return m_simulationStep; } }
110 private int m_taintsToProcessPerStep; 84 internal float LastTimeStep { get; private set; }
85
86 // Physical objects can register for prestep or poststep events
87 public delegate void PreStepAction(float timeStep);
88 public delegate void PostStepAction(float timeStep);
89 public event PreStepAction BeforeStep;
90 public event PreStepAction AfterStep;
111 91
112 // A value of the time now so all the collision and update routines do not have to get their own 92 // 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 93 // Set to 'now' just before all the prims and actors are called for collisions and updates
@@ -121,31 +101,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
121 public bool InTaintTime { get; private set; } 101 public bool InTaintTime { get; private set; }
122 102
123 // Pinned memory used to pass step information between managed and unmanaged 103 // Pinned memory used to pass step information between managed and unmanaged
124 private int m_maxCollisionsPerFrame; 104 internal int m_maxCollisionsPerFrame;
125 private CollisionDesc[] m_collisionArray; 105 internal CollisionDesc[] m_collisionArray;
126 private GCHandle m_collisionArrayPinnedHandle;
127 106
128 private int m_maxUpdatesPerFrame; 107 internal int m_maxUpdatesPerFrame;
129 private EntityProperties[] m_updateArray; 108 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 109
139 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 110 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
140 public const uint GROUNDPLANE_ID = 1; 111 public const uint GROUNDPLANE_ID = 1;
141 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here 112 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
142 113
143 private float m_waterLevel; 114 public float SimpleWaterLevel { get; set; }
144 public BSTerrainManager TerrainManager { get; private set; } 115 public BSTerrainManager TerrainManager { get; private set; }
145 116
146 public ConfigurationParameters Params 117 public ConfigurationParameters Params
147 { 118 {
148 get { return m_params[0]; } 119 get { return UnmanagedParams[0]; }
149 } 120 }
150 public Vector3 DefaultGravity 121 public Vector3 DefaultGravity
151 { 122 {
@@ -157,8 +128,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
157 get { return Params.gravity; } 128 get { return Params.gravity; }
158 } 129 }
159 130
160 public float MaximumObjectMass { get; private set; }
161
162 // When functions in the unmanaged code must be called, it is only 131 // 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 132 // done at a known time just before the simulation step. The taint
164 // system saves all these function calls and executes them in 133 // system saves all these function calls and executes them in
@@ -181,13 +150,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
181 150
182 // A pointer to an instance if this structure is passed to the C++ code 151 // 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. 152 // Used to pass basic configuration values to the unmanaged code.
184 ConfigurationParameters[] m_params; 153 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 154
192 // Sometimes you just have to log everything. 155 // Sometimes you just have to log everything.
193 public Logging.LogWriter PhysicsLogging; 156 public Logging.LogWriter PhysicsLogging;
@@ -195,15 +158,24 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
195 private string m_physicsLoggingDir; 158 private string m_physicsLoggingDir;
196 private string m_physicsLoggingPrefix; 159 private string m_physicsLoggingPrefix;
197 private int m_physicsLoggingFileMinutes; 160 private int m_physicsLoggingFileMinutes;
161 private bool m_physicsLoggingDoFlush;
162 private bool m_physicsPhysicalDumpEnabled;
163 public float PhysicsMetricDumpFrames { get; set; }
198 // 'true' of the vehicle code is to log lots of details 164 // 'true' of the vehicle code is to log lots of details
199 public bool VehicleLoggingEnabled { get; private set; } 165 public bool VehicleLoggingEnabled { get; private set; }
166 public bool VehiclePhysicalLoggingEnabled { get; private set; }
200 167
201 #region Construction and Initialization 168 #region Construction and Initialization
202 public BSScene(string identifier) 169 public BSScene(string engineType, string identifier)
203 { 170 {
204 m_initialized = false; 171 m_initialized = false;
205 // we are passed the name of the region we're working for. 172
173 // The name of the region we're working for is passed to us. Keep for identification.
206 RegionName = identifier; 174 RegionName = identifier;
175
176 // Set identifying variables in the PhysicsScene interface.
177 EngineType = engineType;
178 Name = EngineType + "/" + RegionName;
207 } 179 }
208 180
209 public override void Initialise(IMesher meshmerizer, IConfigSource config) 181 public override void Initialise(IMesher meshmerizer, IConfigSource config)
@@ -216,17 +188,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
216 Shapes = new BSShapeCollection(this); 188 Shapes = new BSShapeCollection(this);
217 189
218 // Allocate pinned memory to pass parameters. 190 // Allocate pinned memory to pass parameters.
219 m_params = new ConfigurationParameters[1]; 191 UnmanagedParams = new ConfigurationParameters[1];
220 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
221 192
222 // Set default values for physics parameters plus any overrides from the ini file 193 // Set default values for physics parameters plus any overrides from the ini file
223 GetInitialParameterValues(config); 194 GetInitialParameterValues(config);
224 195
225 // allocate more pinned memory close to the above in an attempt to get the memory all together 196 // Get the connection to the physics engine (could be native or one of many DLLs)
226 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; 197 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 198
231 // Enable very detailed logging. 199 // Enable very detailed logging.
232 // By creating an empty logger when not logging, the log message invocation code 200 // By creating an empty logger when not logging, the log message invocation code
@@ -234,28 +202,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
234 if (m_physicsLoggingEnabled) 202 if (m_physicsLoggingEnabled)
235 { 203 {
236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 204 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
205 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
237 } 206 }
238 else 207 else
239 { 208 {
240 PhysicsLogging = new Logging.LogWriter(); 209 PhysicsLogging = new Logging.LogWriter();
241 } 210 }
242 211
243 // If Debug logging level, enable logging from the unmanaged code 212 // Allocate memory for returning of the updates and collisions from the physics engine
244 m_DebugLogCallbackHandle = null; 213 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
245 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 214 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 215
260 // The bounding box for the simulated world. The origin is 0,0,0 unless we're 216 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
261 // a child in a mega-region. 217 // a child in a mega-region.
@@ -263,18 +219,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
263 // area. It tracks active objects no matter where they are. 219 // area. It tracks active objects no matter where they are.
264 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 220 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
265 221
266 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 222 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 223
272 Constraints = new BSConstraintCollection(World); 224 Constraints = new BSConstraintCollection(World);
273 225
274 TerrainManager = new BSTerrainManager(this); 226 TerrainManager = new BSTerrainManager(this);
275 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 227 TerrainManager.CreateInitialGroundPlaneAndTerrain();
276 228
277 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); 229 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
278 230
279 InTaintTime = false; 231 InTaintTime = false;
280 m_initialized = true; 232 m_initialized = true;
@@ -285,9 +237,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
285 private void GetInitialParameterValues(IConfigSource config) 237 private void GetInitialParameterValues(IConfigSource config)
286 { 238 {
287 ConfigurationParameters parms = new ConfigurationParameters(); 239 ConfigurationParameters parms = new ConfigurationParameters();
288 m_params[0] = parms; 240 UnmanagedParams[0] = parms;
289 241
290 SetParameterDefaultValues(); 242 BSParam.SetParameterDefaultValues(this);
291 243
292 if (config != null) 244 if (config != null)
293 { 245 {
@@ -295,19 +247,34 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
295 IConfig pConfig = config.Configs["BulletSim"]; 247 IConfig pConfig = config.Configs["BulletSim"];
296 if (pConfig != null) 248 if (pConfig != null)
297 { 249 {
298 SetParameterConfigurationValues(pConfig); 250 BSParam.SetParameterConfigurationValues(this, pConfig);
251
252 // There are two Bullet implementations to choose from
253 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
299 254
300 // Very detailed logging for physics debugging 255 // Very detailed logging for physics debugging
256 // TODO: the boolean values can be moved to the normal parameter processing.
301 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 257 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
302 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 258 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
303 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); 259 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
304 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 260 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
261 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
262 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
305 // Very detailed logging for vehicle debugging 263 // Very detailed logging for vehicle debugging
306 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 264 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
265 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
307 266
308 // Do any replacements in the parameters 267 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 268 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
310 } 269 }
270
271 // The material characteristics.
272 BSMaterials.InitializeFromDefaults(Params);
273 if (pConfig != null)
274 {
275 // Let the user add new and interesting material property values.
276 BSMaterials.InitializefromParameters(pConfig);
277 }
311 } 278 }
312 } 279 }
313 280
@@ -326,16 +293,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
326 return ret; 293 return ret;
327 } 294 }
328 295
329 // Called directly from unmanaged code so don't do much 296 // Select the connection to the actual Bullet implementation.
330 private void BulletLogger(string msg) 297 // The main engine selection is the engineName up to the first hypen.
298 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
299 // is passed to the engine to do its special selection, etc.
300 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
331 { 301 {
332 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 302 // For the moment, do a simple switch statement.
333 } 303 // Someday do fancyness with looking up the interfaces in the assembly.
304 BSAPITemplate ret = null;
334 305
335 // Called directly from unmanaged code so don't do much 306 string selectionName = engineName.ToLower();
336 private void BulletLoggerPhysLog(string msg) 307 int hyphenIndex = engineName.IndexOf("-");
337 { 308 if (hyphenIndex > 0)
338 DetailLog("[BULLETS UNMANAGED]:" + msg); 309 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
310
311 switch (selectionName)
312 {
313 case "bulletunmanaged":
314 ret = new BSAPIUnman(engineName, this);
315 break;
316 case "bulletxna":
317 ret = new BSAPIXNA(engineName, this);
318 break;
319 }
320
321 if (ret == null)
322 {
323 m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
324 }
325 else
326 {
327 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
328 }
329
330 return ret;
339 } 331 }
340 332
341 public override void Dispose() 333 public override void Dispose()
@@ -345,8 +337,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
345 // make sure no stepping happens while we're deleting stuff 337 // make sure no stepping happens while we're deleting stuff
346 m_initialized = false; 338 m_initialized = false;
347 339
348 TerrainManager.ReleaseGroundPlaneAndTerrain();
349
350 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) 340 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
351 { 341 {
352 kvp.Value.Destroy(); 342 kvp.Value.Destroy();
@@ -366,8 +356,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
366 Shapes = null; 356 Shapes = null;
367 } 357 }
368 358
359 if (TerrainManager != null)
360 {
361 TerrainManager.ReleaseGroundPlaneAndTerrain();
362 TerrainManager.Dispose();
363 TerrainManager = null;
364 }
365
369 // Anything left in the unmanaged code should be cleaned out 366 // Anything left in the unmanaged code should be cleaned out
370 BulletSimAPI.Shutdown2(World.ptr); 367 PE.Shutdown(World);
371 368
372 // Not logging any more 369 // Not logging any more
373 PhysicsLogging.Close(); 370 PhysicsLogging.Close();
@@ -389,12 +386,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
389 if (!m_initialized) return null; 386 if (!m_initialized) return null;
390 387
391 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 388 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
392 lock (PhysObjects) PhysObjects.Add(localID, actor); 389 lock (PhysObjects)
390 PhysObjects.Add(localID, actor);
393 391
394 // TODO: Remove kludge someday. 392 // TODO: Remove kludge someday.
395 // We must generate a collision for avatars whether they collide or not. 393 // We must generate a collision for avatars whether they collide or not.
396 // This is required by OpenSim to update avatar animations, etc. 394 // This is required by OpenSim to update avatar animations, etc.
397 lock (m_avatars) m_avatars.Add(actor); 395 lock (m_avatars)
396 m_avatars.Add(actor);
398 397
399 return actor; 398 return actor;
400 } 399 }
@@ -410,9 +409,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
410 { 409 {
411 try 410 try
412 { 411 {
413 lock (PhysObjects) PhysObjects.Remove(actor.LocalID); 412 lock (PhysObjects)
413 PhysObjects.Remove(bsactor.LocalID);
414 // Remove kludge someday 414 // Remove kludge someday
415 lock (m_avatars) m_avatars.Remove(bsactor); 415 lock (m_avatars)
416 m_avatars.Remove(bsactor);
416 } 417 }
417 catch (Exception e) 418 catch (Exception e)
418 { 419 {
@@ -421,6 +422,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
421 bsactor.Destroy(); 422 bsactor.Destroy();
422 // bsactor.dispose(); 423 // bsactor.dispose();
423 } 424 }
425 else
426 {
427 m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
428 LogHeader, actor.LocalID, actor.GetType().Name);
429 }
424 } 430 }
425 431
426 public override void RemovePrim(PhysicsActor prim) 432 public override void RemovePrim(PhysicsActor prim)
@@ -474,41 +480,56 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
474 // Simulate one timestep 480 // Simulate one timestep
475 public override float Simulate(float timeStep) 481 public override float Simulate(float timeStep)
476 { 482 {
483 // prevent simulation until we've been initialized
484 if (!m_initialized) return 5.0f;
485
486 LastTimeStep = timeStep;
487
477 int updatedEntityCount = 0; 488 int updatedEntityCount = 0;
478 IntPtr updatedEntitiesPtr;
479 int collidersCount = 0; 489 int collidersCount = 0;
480 IntPtr collidersPtr;
481 490
482 int beforeTime = 0; 491 int beforeTime = 0;
483 int simTime = 0; 492 int simTime = 0;
484 493
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 494 // update the prim states while we know the physics engine is not busy
489 int numTaints = _taintOperations.Count; 495 int numTaints = _taintOperations.Count;
496
497 InTaintTime = true; // Only used for debugging so locking is not necessary.
498
499 ProcessTaints();
500
501 // Some of the physical objects requre individual, pre-step calls
502 // (vehicles and avatar movement, in particular)
503 TriggerPreStepEvent(timeStep);
504
505 // the prestep actions might have added taints
506 numTaints += _taintOperations.Count;
490 ProcessTaints(); 507 ProcessTaints();
491 508
492 // Some of the prims operate with special vehicle properties 509 InTaintTime = false; // Only used for debugging so locking is not necessary.
493 ProcessVehicles(timeStep); 510
494 ProcessTaints(); // the vehicles might have added taints 511 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
512 // Only enable this in a limited test world with few objects.
513 if (m_physicsPhysicalDumpEnabled)
514 PE.DumpAllInfo(World);
495 515
496 // step the physical world one interval 516 // step the physical world one interval
497 m_simulationStep++; 517 m_simulationStep++;
498 int numSubSteps = 0; 518 int numSubSteps = 0;
499
500 try 519 try
501 { 520 {
502 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 521 if (PhysicsLogging.Enabled)
503 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 522 beforeTime = Util.EnvironmentTickCount();
504 523
505 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 524 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
506 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
507 525
508 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 526 if (PhysicsLogging.Enabled)
509 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 527 {
510 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 528 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
511 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 529 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
530 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
531 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
532 }
512 } 533 }
513 catch (Exception e) 534 catch (Exception e)
514 { 535 {
@@ -520,9 +541,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
520 collidersCount = 0; 541 collidersCount = 0;
521 } 542 }
522 543
523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 544 if ((m_simulationStep % PhysicsMetricDumpFrames) == 0)
545 PE.DumpPhysicsStatistics(World);
524 546
525 // Get a value for 'now' so all the collision and update routines don't have to get their own 547 // Get a value for 'now' so all the collision and update routines don't have to get their own.
526 SimulationNowTime = Util.EnvironmentTickCount(); 548 SimulationNowTime = Util.EnvironmentTickCount();
527 549
528 // If there were collisions, process them by sending the event to the prim. 550 // If there were collisions, process them by sending the event to the prim.
@@ -535,8 +557,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
535 uint cB = m_collisionArray[ii].bID; 557 uint cB = m_collisionArray[ii].bID;
536 Vector3 point = m_collisionArray[ii].point; 558 Vector3 point = m_collisionArray[ii].point;
537 Vector3 normal = m_collisionArray[ii].normal; 559 Vector3 normal = m_collisionArray[ii].normal;
538 SendCollision(cA, cB, point, normal, 0.01f); 560 float penetration = m_collisionArray[ii].penetration;
539 SendCollision(cB, cA, point, -normal, 0.01f); 561 SendCollision(cA, cB, point, normal, penetration);
562 SendCollision(cB, cA, point, -normal, penetration);
540 } 563 }
541 } 564 }
542 565
@@ -562,12 +585,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
562 585
563 // Objects that are done colliding are removed from the ObjectsWithCollisions list. 586 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
564 // Not done above because it is inside an iteration of ObjectWithCollisions. 587 // Not done above because it is inside an iteration of ObjectWithCollisions.
588 // This complex collision processing is required to create an empty collision
589 // event call after all real collisions have happened on an object. This enables
590 // the simulator to generate the 'collision end' event.
565 if (ObjectsWithNoMoreCollisions.Count > 0) 591 if (ObjectsWithNoMoreCollisions.Count > 0)
566 { 592 {
567 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) 593 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
568 ObjectsWithCollisions.Remove(po); 594 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear(); 595 ObjectsWithNoMoreCollisions.Clear();
570 } 596 }
597 // Done with collisions.
571 598
572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 599 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
573 if (updatedEntityCount > 0) 600 if (updatedEntityCount > 0)
@@ -583,17 +610,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
583 } 610 }
584 } 611 }
585 612
586 ProcessPostStepTaints(); 613 TriggerPostStepEvent(timeStep);
587 614
588 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. 615 // 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. 616 // Only enable this in a limited test world with few objects.
590 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG 617 if (m_physicsPhysicalDumpEnabled)
618 PE.DumpAllInfo(World);
591 619
592 // The physics engine returns the number of milliseconds it simulated this call. 620 // 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. 621 // 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). 622 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
595 return numSubSteps * m_fixedTimeStep * 1000 * 55; 623 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
596 // return timeStep * 1000 * 55;
597 } 624 }
598 625
599 // Something has collided 626 // Something has collided
@@ -639,12 +666,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
639 666
640 public override void SetWaterLevel(float baseheight) 667 public override void SetWaterLevel(float baseheight)
641 { 668 {
642 m_waterLevel = baseheight; 669 SimpleWaterLevel = baseheight;
643 }
644 // Someday....
645 public float GetWaterLevelAtXYZ(Vector3 loc)
646 {
647 return m_waterLevel;
648 } 670 }
649 671
650 public override void DeleteTerrain() 672 public override void DeleteTerrain()
@@ -681,6 +703,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
681 public override bool IsThreaded { get { return false; } } 703 public override bool IsThreaded { get { return false; } }
682 704
683 #region Taints 705 #region Taints
706 // The simulation execution order is:
707 // Simulate()
708 // DoOneTimeTaints
709 // TriggerPreStepEvent
710 // DoOneTimeTaints
711 // Step()
712 // ProcessAndSendToSimulatorCollisions
713 // ProcessAndSendToSimulatorPropertyUpdates
714 // TriggerPostStepEvent
684 715
685 // Calls to the PhysicsActors can't directly call into the physics engine 716 // 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. 717 // because it might be busy. We delay changes to a known time.
@@ -707,58 +738,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
707 TaintedObject(ident, callback); 738 TaintedObject(ident, callback);
708 } 739 }
709 740
741 private void TriggerPreStepEvent(float timeStep)
742 {
743 PreStepAction actions = BeforeStep;
744 if (actions != null)
745 actions(timeStep);
746
747 }
748
749 private void TriggerPostStepEvent(float timeStep)
750 {
751 PreStepAction actions = AfterStep;
752 if (actions != null)
753 actions(timeStep);
754
755 }
756
710 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 757 // 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 758 // 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. 759 // here just before the physics engine is called to step the simulation.
713 public void ProcessTaints() 760 public void ProcessTaints()
714 { 761 {
715 InTaintTime = true; // Only used for debugging so locking is not necessary.
716 ProcessRegularTaints(); 762 ProcessRegularTaints();
717 ProcessPostTaintTaints(); 763 ProcessPostTaintTaints();
718 InTaintTime = false;
719 } 764 }
720 765
721 private void ProcessRegularTaints() 766 private void ProcessRegularTaints()
722 { 767 {
723 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process 768 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
724 { 769 {
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 770 // swizzle a new list into the list location so we can process what's there
763 List<TaintCallbackEntry> oldList; 771 List<TaintCallbackEntry> oldList;
764 lock (_taintLock) 772 lock (_taintLock)
@@ -797,6 +805,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
797 return; 805 return;
798 } 806 }
799 807
808 // Taints that happen after the normal taint processing but before the simulation step.
800 private void ProcessPostTaintTaints() 809 private void ProcessPostTaintTaints()
801 { 810 {
802 if (_postTaintOperations.Count > 0) 811 if (_postTaintOperations.Count > 0)
@@ -824,45 +833,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
824 } 833 }
825 } 834 }
826 835
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. 836 // Only used for debugging. Does not change state of anything so locking is not necessary.
867 public bool AssertInTaintTime(string whereFrom) 837 public bool AssertInTaintTime(string whereFrom)
868 { 838 {
@@ -870,517 +840,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
870 { 840 {
871 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); 841 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); 842 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. 843 Util.PrintCallStack(DetailLog);
874 } 844 }
875 return InTaintTime; 845 return InTaintTime;
876 } 846 }
877 847
878 #endregion // Taints 848 #endregion // Taints
879 849
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 850 #region IPhysicsParameters
1379 // Get the list of parameters this physics engine supports 851 // Get the list of parameters this physics engine supports
1380 public PhysParameterEntry[] GetParameterList() 852 public PhysParameterEntry[] GetParameterList()
1381 { 853 {
1382 BuildParameterTable(); 854 BSParam.BuildParameterTable();
1383 return SettableParameters; 855 return BSParam.SettableParameters;
1384 } 856 }
1385 857
1386 // Set parameter on a specific or all instances. 858 // Set parameter on a specific or all instances.
@@ -1392,8 +864,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1392 public bool SetPhysicsParameter(string parm, float val, uint localID) 864 public bool SetPhysicsParameter(string parm, float val, uint localID)
1393 { 865 {
1394 bool ret = false; 866 bool ret = false;
1395 ParameterDefn theParam; 867 BSParam.ParameterDefn theParam;
1396 if (TryGetParameter(parm, out theParam)) 868 if (BSParam.TryGetParameter(parm, out theParam))
1397 { 869 {
1398 theParam.setter(this, parm, localID, val); 870 theParam.setter(this, parm, localID, val);
1399 ret = true; 871 ret = true;
@@ -1405,19 +877,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1405 // If the local ID is APPLY_TO_NONE, just change the default value 877 // 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 878 // 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 879 // 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) 880 internal delegate void AssignVal(float x);
881 internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
1409 { 882 {
1410 List<uint> objectIDs = new List<uint>(); 883 List<uint> objectIDs = new List<uint>();
1411 switch (localID) 884 switch (localID)
1412 { 885 {
1413 case PhysParameterEntry.APPLY_TO_NONE: 886 case PhysParameterEntry.APPLY_TO_NONE:
1414 defaultLoc = val; // setting only the default value 887 setDefault(val); // setting only the default value
1415 // This will cause a call into the physical world if some operation is specified (SetOnObject). 888 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1416 objectIDs.Add(TERRAIN_ID); 889 objectIDs.Add(TERRAIN_ID);
1417 TaintedUpdateParameter(parm, objectIDs, val); 890 TaintedUpdateParameter(parm, objectIDs, val);
1418 break; 891 break;
1419 case PhysParameterEntry.APPLY_TO_ALL: 892 case PhysParameterEntry.APPLY_TO_ALL:
1420 defaultLoc = val; // setting ALL also sets the default value 893 setDefault(val); // setting ALL also sets the default value
1421 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); 894 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1422 TaintedUpdateParameter(parm, objectIDs, val); 895 TaintedUpdateParameter(parm, objectIDs, val);
1423 break; 896 break;
@@ -1436,8 +909,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1436 List<uint> xlIDs = lIDs; 909 List<uint> xlIDs = lIDs;
1437 string xparm = parm; 910 string xparm = parm;
1438 TaintedObject("BSScene.UpdateParameterSet", delegate() { 911 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1439 ParameterDefn thisParam; 912 BSParam.ParameterDefn thisParam;
1440 if (TryGetParameter(xparm, out thisParam)) 913 if (BSParam.TryGetParameter(xparm, out thisParam))
1441 { 914 {
1442 if (thisParam.onObject != null) 915 if (thisParam.onObject != null)
1443 { 916 {
@@ -1458,8 +931,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1458 { 931 {
1459 float val = 0f; 932 float val = 0f;
1460 bool ret = false; 933 bool ret = false;
1461 ParameterDefn theParam; 934 BSParam.ParameterDefn theParam;
1462 if (TryGetParameter(parm, out theParam)) 935 if (BSParam.TryGetParameter(parm, out theParam))
1463 { 936 {
1464 val = theParam.getter(this); 937 val = theParam.getter(this);
1465 ret = true; 938 ret = true;
@@ -1470,24 +943,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1470 943
1471 #endregion IPhysicsParameters 944 #endregion IPhysicsParameters
1472 945
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. 946 // Invoke the detailed logger and output something if it's enabled.
1486 public void DetailLog(string msg, params Object[] args) 947 public void DetailLog(string msg, params Object[] args)
1487 { 948 {
1488 PhysicsLogging.Write(msg, args); 949 PhysicsLogging.Write(msg, args);
1489 // Add the Flush() if debugging crashes. Gets all the messages written out. 950 // Add the Flush() if debugging crashes. Gets all the messages written out.
1490 // PhysicsLogging.Flush(); 951 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
1491 } 952 }
1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 953 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1493 public const string DetailLogZero = "0000000000"; 954 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..473ef10 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -45,7 +45,7 @@ public sealed class BSShapeCollection : IDisposable
45 // Description of a Mesh 45 // Description of a Mesh
46 private struct MeshDesc 46 private struct MeshDesc
47 { 47 {
48 public IntPtr ptr; 48 public BulletShape shape;
49 public int referenceCount; 49 public int referenceCount;
50 public DateTime lastReferenced; 50 public DateTime lastReferenced;
51 public UInt64 shapeKey; 51 public UInt64 shapeKey;
@@ -55,7 +55,7 @@ public sealed class BSShapeCollection : IDisposable
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. 55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc 56 private struct HullDesc
57 { 57 {
58 public IntPtr ptr; 58 public BulletShape shape;
59 public int referenceCount; 59 public int referenceCount;
60 public DateTime lastReferenced; 60 public DateTime lastReferenced;
61 public UInt64 shapeKey; 61 public UInt64 shapeKey;
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); 65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); 66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67 67
68 private bool DDetail = false;
69
68 public BSShapeCollection(BSScene physScene) 70 public BSShapeCollection(BSScene physScene)
69 { 71 {
70 PhysicsScene = physScene; 72 PhysicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging
76 // statements can be commented/removed.
77 DDetail = true;
71 } 78 }
72 79
73 public void Dispose() 80 public void Dispose()
@@ -91,7 +98,7 @@ public sealed class BSShapeCollection : IDisposable
91 // higher level dependencies on the shape or body. Mostly used for LinkSets to 98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
92 // remove the physical constraints before the body is destroyed. 99 // remove the physical constraints before the body is destroyed.
93 // Called at taint-time!! 100 // Called at taint-time!!
94 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
95 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
96 { 103 {
97 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
@@ -119,6 +126,11 @@ public sealed class BSShapeCollection : IDisposable
119 return ret; 126 return ret;
120 } 127 }
121 128
129 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
130 {
131 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
132 }
133
122 // Track another user of a body. 134 // Track another user of a body.
123 // We presume the caller has allocated the body. 135 // We presume the caller has allocated the body.
124 // Bodies only have one user so the body is just put into the world if not already there. 136 // Bodies only have one user so the body is just put into the world if not already there.
@@ -126,13 +138,13 @@ public sealed class BSShapeCollection : IDisposable
126 { 138 {
127 lock (m_collectionActivityLock) 139 lock (m_collectionActivityLock)
128 { 140 {
129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); 141 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() 142 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
131 { 143 {
132 if (!BulletSimAPI.IsInWorld2(body.ptr)) 144 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
133 { 145 {
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 146 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); 147 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
136 } 148 }
137 }); 149 });
138 } 150 }
@@ -142,27 +154,27 @@ public sealed class BSShapeCollection : IDisposable
142 // Called when releasing use of a BSBody. BSShape is handled separately. 154 // Called when releasing use of a BSBody. BSShape is handled separately.
143 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) 155 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
144 { 156 {
145 if (body.ptr == IntPtr.Zero) 157 if (!body.HasPhysicalBody)
146 return; 158 return;
147 159
148 lock (m_collectionActivityLock) 160 lock (m_collectionActivityLock)
149 { 161 {
150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() 162 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
151 { 163 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", 164 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
153 body.ID, body, inTaintTime); 165 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up. 166 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body); 167 if (bodyCallback != null) bodyCallback(body);
156 168
157 if (BulletSimAPI.IsInWorld2(body.ptr)) 169 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
158 { 170 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 171 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); 172 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 } 173 }
162 174
163 // Zero any reference to the shape so it is not freed when the body is deleted. 175 // Zero any reference to the shape so it is not freed when the body is deleted.
164 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); 176 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 177 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
166 }); 178 });
167 } 179 }
168 } 180 }
@@ -184,17 +196,17 @@ public sealed class BSShapeCollection : IDisposable
184 { 196 {
185 // There is an existing instance of this mesh. 197 // There is an existing instance of this mesh.
186 meshDesc.referenceCount++; 198 meshDesc.referenceCount++;
187 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", 199 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
188 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 200 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
189 } 201 }
190 else 202 else
191 { 203 {
192 // This is a new reference to a mesh 204 // This is a new reference to a mesh
193 meshDesc.ptr = shape.ptr; 205 meshDesc.shape = shape.Clone();
194 meshDesc.shapeKey = shape.shapeKey; 206 meshDesc.shapeKey = shape.shapeKey;
195 // We keep a reference to the underlying IMesh data so a hull can be built 207 // We keep a reference to the underlying IMesh data so a hull can be built
196 meshDesc.referenceCount = 1; 208 meshDesc.referenceCount = 1;
197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 209 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
198 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 210 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
199 ret = true; 211 ret = true;
200 } 212 }
@@ -207,16 +219,16 @@ public sealed class BSShapeCollection : IDisposable
207 { 219 {
208 // There is an existing instance of this hull. 220 // There is an existing instance of this hull.
209 hullDesc.referenceCount++; 221 hullDesc.referenceCount++;
210 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", 222 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 223 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
212 } 224 }
213 else 225 else
214 { 226 {
215 // This is a new reference to a hull 227 // This is a new reference to a hull
216 hullDesc.ptr = shape.ptr; 228 hullDesc.shape = shape.Clone();
217 hullDesc.shapeKey = shape.shapeKey; 229 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 230 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 231 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 232 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true; 233 ret = true;
222 234
@@ -236,20 +248,20 @@ public sealed class BSShapeCollection : IDisposable
236 // Release the usage of a shape. 248 // Release the usage of a shape.
237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 249 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
238 { 250 {
239 if (shape.ptr == IntPtr.Zero) 251 if (!shape.HasPhysicalShape)
240 return; 252 return;
241 253
242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() 254 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
243 { 255 {
244 if (shape.ptr != IntPtr.Zero) 256 if (shape.HasPhysicalShape)
245 { 257 {
246 if (shape.isNativeShape) 258 if (shape.isNativeShape)
247 { 259 {
248 // Native shapes are not tracked and are released immediately 260 // Native shapes are not tracked and are released immediately
249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 261 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 262 BSScene.DetailLogZero, shape.AddrString, inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape); 263 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 264 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
253 } 265 }
254 else 266 else
255 { 267 {
@@ -286,7 +298,7 @@ public sealed class BSShapeCollection : IDisposable
286 if (shapeCallback != null) shapeCallback(shape); 298 if (shapeCallback != null) shapeCallback(shape);
287 meshDesc.lastReferenced = System.DateTime.Now; 299 meshDesc.lastReferenced = System.DateTime.Now;
288 Meshes[shape.shapeKey] = meshDesc; 300 Meshes[shape.shapeKey] = meshDesc;
289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", 301 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
290 BSScene.DetailLogZero, shape, meshDesc.referenceCount); 302 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
291 303
292 } 304 }
@@ -307,7 +319,7 @@ public sealed class BSShapeCollection : IDisposable
307 319
308 hullDesc.lastReferenced = System.DateTime.Now; 320 hullDesc.lastReferenced = System.DateTime.Now;
309 Hulls[shape.shapeKey] = hullDesc; 321 Hulls[shape.shapeKey] = hullDesc;
310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", 322 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
311 BSScene.DetailLogZero, shape, hullDesc.referenceCount); 323 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 } 324 }
313 } 325 }
@@ -320,57 +332,56 @@ public sealed class BSShapeCollection : IDisposable
320 // Called at taint-time. 332 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) 333 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 { 334 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr)) 335 if (!PhysicsScene.PE.IsCompound(shape))
324 { 336 {
325 // Failed the sanity check!! 337 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", 338 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
327 LogHeader, shape.type, shape.ptr.ToString("X")); 339 LogHeader, shape.type, shape.AddrString);
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", 340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); 341 BSScene.DetailLogZero, shape.type, shape.AddrString);
330 return; 342 return;
331 } 343 }
332 344
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 345 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); 346 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335 347
336 for (int ii = numChildren - 1; ii >= 0; ii--) 348 for (int ii = numChildren - 1; ii >= 0; ii--)
337 { 349 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); 350 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
339 DereferenceAnonCollisionShape(childShape); 351 DereferenceAnonCollisionShape(childShape);
340 } 352 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 353 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
342 } 354 }
343 355
344 // Sometimes we have a pointer to a collision shape but don't know what type it is. 356 // Sometimes we have a pointer to a collision shape but don't know what type it is.
345 // Figure out type and call the correct dereference routine. 357 // Figure out type and call the correct dereference routine.
346 // Called at taint-time. 358 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape) 359 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
348 { 360 {
349 MeshDesc meshDesc; 361 MeshDesc meshDesc;
350 HullDesc hullDesc; 362 HullDesc hullDesc;
351 363
352 BulletShape shapeInfo = new BulletShape(cShape); 364 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 { 365 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; 366 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey; 367 shapeInfo.shapeKey = meshDesc.shapeKey;
357 } 368 }
358 else 369 else
359 { 370 {
360 if (TryGetHullByPtr(cShape, out hullDesc)) 371 if (TryGetHullByPtr(shapeInfo, out hullDesc))
361 { 372 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; 373 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey; 374 shapeInfo.shapeKey = hullDesc.shapeKey;
364 } 375 }
365 else 376 else
366 { 377 {
367 if (BulletSimAPI.IsCompound2(cShape)) 378 if (PhysicsScene.PE.IsCompound(shapeInfo))
368 { 379 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; 380 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 } 381 }
371 else 382 else
372 { 383 {
373 if (BulletSimAPI.IsNativeShape2(cShape)) 384 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
374 { 385 {
375 shapeInfo.isNativeShape = true; 386 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) 387 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
@@ -379,7 +390,7 @@ public sealed class BSShapeCollection : IDisposable
379 } 390 }
380 } 391 }
381 392
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 393 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 394
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) 395 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 396 {
@@ -388,7 +399,7 @@ public sealed class BSShapeCollection : IDisposable
388 else 399 else
389 { 400 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", 401 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); 402 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
392 } 403 }
393 } 404 }
394 405
@@ -408,19 +419,18 @@ public sealed class BSShapeCollection : IDisposable
408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 419 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 { 420 {
410 // an avatar capsule is close to a native shape (it is not shared) 421 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, 422 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
412 FixedShapeKey.KEY_CAPSULE, shapeCallback); 423 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true; 424 ret = true;
415 haveShape = true; 425 haveShape = true;
416 } 426 }
417 427
418 // Compound shapes are handled special as they are rebuilt from scratch. 428 // Compound shapes are handled special as they are rebuilt from scratch.
419 // This isn't too great a hardship since most of the child shapes will already been created. 429 // This isn't too great a hardship since most of the child shapes will have already been created.
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) 430 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 431 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 432 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 433 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true; 434 haveShape = true;
425 } 435 }
426 436
@@ -432,8 +442,9 @@ public sealed class BSShapeCollection : IDisposable
432 return ret; 442 return ret;
433 } 443 }
434 444
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. 445 // Create a mesh, hull or native shape.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 446 // Return 'true' if the prim's shape was changed.
447 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 { 448 {
438 bool ret = false; 449 bool ret = false;
439 bool haveShape = false; 450 bool haveShape = false;
@@ -443,8 +454,9 @@ public sealed class BSShapeCollection : IDisposable
443 // If the prim attributes are simple, this could be a simple Bullet native shape 454 // If the prim attributes are simple, this could be a simple Bullet native shape
444 if (!haveShape 455 if (!haveShape
445 && pbs != null 456 && pbs != null
457 && !pbs.SculptEntry
446 && nativeShapePossible 458 && nativeShapePossible
447 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 459 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
448 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 460 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
449 && pbs.ProfileHollow == 0 461 && pbs.ProfileHollow == 0
450 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 462 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
@@ -453,35 +465,43 @@ public sealed class BSShapeCollection : IDisposable
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 465 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 466 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
455 { 467 {
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 468 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
469 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
470 if (prim.PhysShape.HasPhysicalShape)
471 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
472
473 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
474 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
475
476 // 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) 477 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 478 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 { 479 {
460 haveShape = true; 480 haveShape = true;
461 if (forceRebuild 481 if (forceRebuild
462 || prim.Scale != prim.Size 482 || prim.Scale != scaleOfExistingShape
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 483 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 484 )
465 { 485 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 486 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 487 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 488 }
489 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
490 prim.LocalID, forceRebuild, ret, prim.PhysShape);
471 } 491 }
472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 492 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
473 { 493 {
474 haveShape = true; 494 haveShape = true;
475 if (forceRebuild 495 if (forceRebuild
476 || prim.Scale != prim.Size 496 || prim.Scale != scaleOfExistingShape
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 497 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 498 )
479 { 499 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 500 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 501 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 502 }
503 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
504 prim.LocalID, forceRebuild, ret, prim.PhysShape);
485 } 505 }
486 } 506 }
487 507
@@ -494,23 +514,24 @@ public sealed class BSShapeCollection : IDisposable
494 return ret; 514 return ret;
495 } 515 }
496 516
517 // return 'true' if the prim's shape was changed.
497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 518 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
498 { 519 {
499 520
500 bool ret = false; 521 bool ret = false;
501 // Note that if it's a native shape, the check for physical/non-physical is not 522 // Note that if it's a native shape, the check for physical/non-physical is not
502 // made. Native shapes work in either case. 523 // made. Native shapes work in either case.
503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 524 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
504 { 525 {
505 // Update prim.BSShape to reference a hull of this shape. 526 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 527 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 528 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 529 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 530 }
510 else 531 else
511 { 532 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 533 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 534 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 535 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 536 }
516 return ret; 537 return ret;
@@ -528,9 +549,10 @@ public sealed class BSShapeCollection : IDisposable
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 549 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 550
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 551 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 552 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 553 prim.LocalID, newShape, prim.Scale);
533 554
555 // native shapes are scaled by Bullet
534 prim.PhysShape = newShape; 556 prim.PhysShape = newShape;
535 return true; 557 return true;
536 } 558 }
@@ -550,20 +572,17 @@ public sealed class BSShapeCollection : IDisposable
550 572
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 573 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
552 { 574 {
553 // The proper scale has been calculated in the prim. 575
554 newShape = new BulletShape( 576 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 577 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 578 }
559 else 579 else
560 { 580 {
561 // Native shapes are scaled in Bullet so set the scaling to the size 581 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size; 582 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
563 nativeShapeData.Scale = prim.Scale; 583
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 } 584 }
566 if (newShape.ptr == IntPtr.Zero) 585 if (!newShape.HasPhysicalShape)
567 { 586 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 587 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType); 588 LogHeader, prim.LocalID, shapeType);
@@ -580,7 +599,7 @@ public sealed class BSShapeCollection : IDisposable
580 // Called at taint-time! 599 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 600 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 { 601 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero); 602 BulletShape newShape = new BulletShape();
584 603
585 float lod; 604 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 605 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -589,7 +608,7 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 608 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 609 return false;
591 610
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 611 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 612 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
594 613
595 // Since we're recreating new, get rid of the reference to the previous shape 614 // Since we're recreating new, get rid of the reference to the previous shape
@@ -601,8 +620,6 @@ public sealed class BSShapeCollection : IDisposable
601 620
602 ReferenceShape(newShape); 621 ReferenceShape(newShape);
603 622
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape; 623 prim.PhysShape = newShape;
607 624
608 return true; // 'true' means a new shape has been added to this prim 625 return true; // 'true' means a new shape has been added to this prim
@@ -610,18 +627,18 @@ public sealed class BSShapeCollection : IDisposable
610 627
611 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 628 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
612 { 629 {
630 BulletShape newShape = new BulletShape();
613 IMesh meshData = null; 631 IMesh meshData = null;
614 IntPtr meshPtr = IntPtr.Zero; 632
615 MeshDesc meshDesc; 633 MeshDesc meshDesc;
616 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 634 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
617 { 635 {
618 // If the mesh has already been built just use it. 636 // If the mesh has already been built just use it.
619 meshPtr = meshDesc.ptr; 637 newShape = meshDesc.shape.Clone();
620 } 638 }
621 else 639 else
622 { 640 {
623 // Pass false for physicalness as this creates some sort of bounding box which we don't need 641 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
625 642
626 if (meshData != null) 643 if (meshData != null)
627 { 644 {
@@ -640,11 +657,10 @@ public sealed class BSShapeCollection : IDisposable
640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 657 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 658 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
642 659
643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 660 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 661 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
645 } 662 }
646 } 663 }
647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
648 newShape.shapeKey = newMeshKey; 664 newShape.shapeKey = newMeshKey;
649 665
650 return newShape; 666 return newShape;
@@ -663,7 +679,7 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 679 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 680 return false;
665 681
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 682 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 683 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 684
669 // Remove usage of the previous shape. 685 // Remove usage of the previous shape.
@@ -674,8 +690,6 @@ public sealed class BSShapeCollection : IDisposable
674 690
675 ReferenceShape(newShape); 691 ReferenceShape(newShape);
676 692
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape; 693 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim 694 return true; // 'true' means a new shape has been added to this prim
681 } 695 }
@@ -684,18 +698,20 @@ public sealed class BSShapeCollection : IDisposable
684 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 698 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
685 { 699 {
686 700
701 BulletShape newShape = new BulletShape();
687 IntPtr hullPtr = IntPtr.Zero; 702 IntPtr hullPtr = IntPtr.Zero;
703
688 HullDesc hullDesc; 704 HullDesc hullDesc;
689 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 705 if (Hulls.TryGetValue(newHullKey, out hullDesc))
690 { 706 {
691 // If the hull shape already is created, just use it. 707 // If the hull shape already is created, just use it.
692 hullPtr = hullDesc.ptr; 708 newShape = hullDesc.shape.Clone();
693 } 709 }
694 else 710 else
695 { 711 {
696 // Build a new hull in the physical world 712 // 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 713 // Pass true for physicalness as this creates some sort of bounding box which we don't need
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 714 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
699 if (meshData != null) 715 if (meshData != null)
700 { 716 {
701 717
@@ -777,14 +793,13 @@ public sealed class BSShapeCollection : IDisposable
777 } 793 }
778 } 794 }
779 // create the hull data structure in Bullet 795 // create the hull data structure in Bullet
780 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); 796 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
781 } 797 }
782 } 798 }
783 799
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey; 800 newShape.shapeKey = newHullKey;
786 801
787 return newShape; // 'true' means a new shape has been added to this prim 802 return newShape;
788 } 803 }
789 804
790 // Callback from convex hull creater with a newly created hull. 805 // Callback from convex hull creater with a newly created hull.
@@ -803,13 +818,13 @@ public sealed class BSShapeCollection : IDisposable
803 // Don't need to do this as the shape is freed when the new root shape is created below. 818 // 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); 819 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805 820
806 BulletShape cShape = new BulletShape( 821
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND); 822 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
808 823
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 824 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 825 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 826 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 827 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 828 prim.LocalID, cShape, prim.PhysShape);
814 829
815 prim.PhysShape = cShape; 830 prim.PhysShape = cShape;
@@ -822,14 +837,14 @@ public sealed class BSShapeCollection : IDisposable
822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) 837 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
823 { 838 {
824 // level of detail based on size and type of the object 839 // level of detail based on size and type of the object
825 float lod = PhysicsScene.MeshLOD; 840 float lod = BSParam.MeshLOD;
826 if (pbs.SculptEntry) 841 if (pbs.SculptEntry)
827 lod = PhysicsScene.SculptLOD; 842 lod = BSParam.SculptLOD;
828 843
829 // Mega prims usually get more detail because one can interact with shape approximations at this size. 844 // 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)); 845 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 846 if (maxAxis > BSParam.MeshMegaPrimThreshold)
832 lod = PhysicsScene.MeshMegaPrimLOD; 847 lod = BSParam.MeshMegaPrimLOD;
833 848
834 retLod = lod; 849 retLod = lod;
835 return pbs.GetMeshKey(size, lod); 850 return pbs.GetMeshKey(size, lod);
@@ -851,7 +866,7 @@ public sealed class BSShapeCollection : IDisposable
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 866 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 { 867 {
853 // If the shape was successfully created, nothing more to do 868 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero) 869 if (newShape.HasPhysicalShape)
855 return newShape; 870 return newShape;
856 871
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 872 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
@@ -859,8 +874,7 @@ public sealed class BSShapeCollection : IDisposable
859 { 874 {
860 prim.LastAssetBuildFailed = true; 875 prim.LastAssetBuildFailed = true;
861 BSPhysObject xprim = prim; 876 BSPhysObject xprim = prim;
862 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", 877 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lastFailed={1}", prim.LocalID, prim.LastAssetBuildFailed);
863 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
864 Util.FireAndForget(delegate 878 Util.FireAndForget(delegate
865 { 879 {
866 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; 880 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@@ -869,19 +883,34 @@ public sealed class BSShapeCollection : IDisposable
869 BSPhysObject yprim = xprim; // probably not necessary, but, just in case. 883 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
870 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) 884 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
871 { 885 {
872 if (!yprim.BaseShape.SculptEntry) 886 bool assetFound = false; // DEBUG DEBUG
873 return; 887 string mismatchIDs = String.Empty; // DEBUG DEBUG
874 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) 888 if (yprim.BaseShape.SculptEntry)
875 return; 889 {
876 890 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
877 yprim.BaseShape.SculptData = asset.Data; 891 {
878 // This will cause the prim to see that the filler shape is not the right 892 yprim.BaseShape.SculptData = asset.Data;
879 // one and try again to build the object. 893 // This will cause the prim to see that the filler shape is not the right
880 // No race condition with the normal shape setting since the rebuild is at taint time. 894 // one and try again to build the object.
881 yprim.ForceBodyShapeRebuild(false); 895 // No race condition with the normal shape setting since the rebuild is at taint time.
896 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
897 assetFound = true;
898 }
899 else
900 {
901 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
902 }
903 }
904 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
905 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
882 906
883 }); 907 });
884 } 908 }
909 else
910 {
911 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
912 LogHeader, PhysicsScene.Name);
913 }
885 }); 914 });
886 } 915 }
887 else 916 else
@@ -893,9 +922,9 @@ public sealed class BSShapeCollection : IDisposable
893 } 922 }
894 } 923 }
895 924
896 // While we figure out the real problem, stick a simple native shape on the object. 925 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
897 BulletShape fillinShape = 926 BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 927 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
899 928
900 return fillinShape; 929 return fillinShape;
901 } 930 }
@@ -904,19 +933,19 @@ public sealed class BSShapeCollection : IDisposable
904 // Updates prim.BSBody with the information about the new body if one is created. 933 // Updates prim.BSBody with the information about the new body if one is created.
905 // Returns 'true' if an object was actually created. 934 // Returns 'true' if an object was actually created.
906 // Called at taint-time. 935 // Called at taint-time.
907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 936 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape,
908 BodyDestructionCallback bodyCallback) 937 BodyDestructionCallback bodyCallback)
909 { 938 {
910 bool ret = false; 939 bool ret = false;
911 940
912 // the mesh, hull or native shape must have already been created in Bullet 941 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 942 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
914 943
915 // If there is an existing body, verify it's of an acceptable type. 944 // 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. 945 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
917 if (!mustRebuild) 946 if (!mustRebuild)
918 { 947 {
919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); 948 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 949 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 950 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
922 { 951 {
@@ -931,20 +960,16 @@ public sealed class BSShapeCollection : IDisposable
931 DereferenceBody(prim.PhysBody, true, bodyCallback); 960 DereferenceBody(prim.PhysBody, true, bodyCallback);
932 961
933 BulletBody aBody; 962 BulletBody aBody;
934 IntPtr bodyPtr = IntPtr.Zero;
935 if (prim.IsSolid) 963 if (prim.IsSolid)
936 { 964 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 965 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 966 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 } 967 }
941 else 968 else
942 { 969 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 970 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 971 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 } 972 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 973
949 ReferenceBody(aBody, true); 974 ReferenceBody(aBody, true);
950 975
@@ -956,13 +981,13 @@ public sealed class BSShapeCollection : IDisposable
956 return ret; 981 return ret;
957 } 982 }
958 983
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) 984 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
960 { 985 {
961 bool ret = false; 986 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc(); 987 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values) 988 foreach (MeshDesc md in Meshes.Values)
964 { 989 {
965 if (md.ptr == addr) 990 if (md.shape.ReferenceSame(shape))
966 { 991 {
967 foundDesc = md; 992 foundDesc = md;
968 ret = true; 993 ret = true;
@@ -974,13 +999,13 @@ public sealed class BSShapeCollection : IDisposable
974 return ret; 999 return ret;
975 } 1000 }
976 1001
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) 1002 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
978 { 1003 {
979 bool ret = false; 1004 bool ret = false;
980 HullDesc foundDesc = new HullDesc(); 1005 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values) 1006 foreach (HullDesc hd in Hulls.Values)
982 { 1007 {
983 if (hd.ptr == addr) 1008 if (hd.shape.ReferenceSame(shape))
984 { 1009 {
985 foundDesc = hd; 1010 foundDesc = hd;
986 ret = true; 1011 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..2e9db39 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -62,11 +62,12 @@ public abstract class BSTerrainPhys : IDisposable
62 ID = id; 62 ID = id;
63 } 63 }
64 public abstract void Dispose(); 64 public abstract void Dispose();
65 public abstract float GetHeightAtXYZ(Vector3 pos); 65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
66} 67}
67 68
68// ========================================================================================== 69// ==========================================================================================
69public sealed class BSTerrainManager 70public sealed class BSTerrainManager : IDisposable
70{ 71{
71 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; 72 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
72 73
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager
75 public const float HEIGHT_INITIALIZATION = 24.987f; 76 public const float HEIGHT_INITIALIZATION = 24.987f;
76 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; 77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
77 public const float HEIGHT_GETHEIGHT_RET = 24.765f; 78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
78 80
79 // If the min and max height are equal, we reduce the min by this 81 // If the min and max height are equal, we reduce the min by this
80 // amount to make sure that a bounding box is built for the terrain. 82 // amount to make sure that a bounding box is built for the terrain.
81 public const float HEIGHT_EQUAL_FUDGE = 0.2f; 83 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
82 84
83 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
84
85 // Until the whole simulator is changed to pass us the region size, we rely on constants. 85 // Until the whole simulator is changed to pass us the region size, we rely on constants.
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 87
@@ -122,25 +122,28 @@ public sealed class BSTerrainManager
122 MegaRegionParentPhysicsScene = null; 122 MegaRegionParentPhysicsScene = null;
123 } 123 }
124 124
125 public void Dispose()
126 {
127 ReleaseGroundPlaneAndTerrain();
128 }
129
125 // Create the initial instance of terrain and the underlying ground plane. 130 // Create the initial instance of terrain and the underlying ground plane.
126 // This is called from the initialization routine so we presume it is 131 // This is called from the initialization routine so we presume it is
127 // safe to call Bullet in real time. We hope no one is moving prims around yet. 132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
128 public void CreateInitialGroundPlaneAndTerrain() 133 public void CreateInitialGroundPlaneAndTerrain()
129 { 134 {
130 // The ground plane is here to catch things that are trying to drop to negative infinity 135 // The ground plane is here to catch things that are trying to drop to negative infinity
131 BulletShape groundPlaneShape = new BulletShape( 136 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE); 138 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 139
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 140 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
136 Vector3.Zero, Quaternion.Identity)); 141 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
137 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
138 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
139 // Ground plane does not move 142 // Ground plane does not move
140 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 143 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
141 // Everything collides with the ground plane. 144 // Everything collides with the ground plane.
142 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 145 m_groundPlane.collisionType = CollisionType.Groundplane;
143 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 146 m_groundPlane.ApplyCollisionMask(PhysicsScene);
144 147
145 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 148 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
146 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
@@ -150,13 +153,13 @@ public sealed class BSTerrainManager
150 // Release all the terrain structures we might have allocated 153 // Release all the terrain structures we might have allocated
151 public void ReleaseGroundPlaneAndTerrain() 154 public void ReleaseGroundPlaneAndTerrain()
152 { 155 {
153 if (m_groundPlane.ptr != IntPtr.Zero) 156 if (m_groundPlane.HasPhysicalBody)
154 { 157 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) 158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
156 { 159 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); 160 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane);
158 } 161 }
159 m_groundPlane.ptr = IntPtr.Zero; 162 m_groundPlane.Clear();
160 } 163 }
161 164
162 ReleaseTerrain(); 165 ReleaseTerrain();
@@ -165,17 +168,22 @@ public sealed class BSTerrainManager
165 // Release all the terrain we have allocated 168 // Release all the terrain we have allocated
166 public void ReleaseTerrain() 169 public void ReleaseTerrain()
167 { 170 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) 171 lock (m_terrains)
169 { 172 {
170 kvp.Value.Dispose(); 173 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
174 {
175 kvp.Value.Dispose();
176 }
177 m_terrains.Clear();
171 } 178 }
172 m_terrains.Clear();
173 } 179 }
174 180
175 // The simulator wants to set a new heightmap for the terrain. 181 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) { 182 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap; 183 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 184 // If there are multiple requests for changes to the same terrain between ticks,
185 // only do that last one.
186 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
179 { 187 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 188 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 { 189 {
@@ -211,6 +219,7 @@ public sealed class BSTerrainManager
211 // terrain shape is created and added to the body. 219 // terrain shape is created and added to the body.
212 // This call is most often used to update the heightMap and parameters of the terrain. 220 // This call is most often used to update the heightMap and parameters of the terrain.
213 // (The above does suggest that some simplification/refactoring is in order.) 221 // (The above does suggest that some simplification/refactoring is in order.)
222 // Called during taint-time.
214 private void UpdateTerrain(uint id, float[] heightMap, 223 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 { 225 {
@@ -220,7 +229,7 @@ public sealed class BSTerrainManager
220 // Find high and low points of passed heightmap. 229 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum 230 // The min and max passed in is usually the area objects can be in (maximum
222 // object height, for instance). The terrain wants the bounding box for the 231 // object height, for instance). The terrain wants the bounding box for the
223 // terrain so we replace passed min and max Z with the actual terrain min/max Z. 232 // terrain so replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue; 233 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 234 float maxZ = float.MinValue;
226 foreach (float height in heightMap) 235 foreach (float height in heightMap)
@@ -238,15 +247,15 @@ public sealed class BSTerrainManager
238 247
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 248 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240 249
241 BSTerrainPhys terrainPhys; 250 lock (m_terrains)
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 { 251 {
244 // There is already a terrain in this spot. Free the old and build the new. 252 BSTerrainPhys terrainPhys;
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 { 254 {
255 // There is already a terrain in this spot. Free the old and build the new.
256 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
258
250 // Remove old terrain from the collection 259 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase); 260 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using. 261 // Release any physical memory it may be using.
@@ -271,35 +280,24 @@ public sealed class BSTerrainManager
271 // I hate doing this, but just bail 280 // I hate doing this, but just bail
272 return; 281 return;
273 } 282 }
274 }); 283 }
275 } 284 else
276 else 285 {
277 { 286 // We don't know about this terrain so either we are creating a new terrain or
278 // We don't know about this terrain so either we are creating a new terrain or 287 // our mega-prim child is giving us a new terrain to add to the phys world
279 // our mega-prim child is giving us a new terrain to add to the phys world
280
281 // if this is a child terrain, calculate a unique terrain id
282 uint newTerrainID = id;
283 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
284 newTerrainID = ++m_terrainCount;
285
286 float[] heightMapX = heightMap;
287 Vector3 minCoordsX = minCoords;
288 Vector3 maxCoordsX = maxCoords;
289 288
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 289 // if this is a child terrain, calculate a unique terrain id
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 290 uint newTerrainID = id;
291 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
292 newTerrainID = ++m_terrainCount;
292 293
293 // Code that must happen at taint-time 294 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() 295 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
295 {
296 DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
297 BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
298 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 296 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys); 297 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300 298
301 m_terrainModified = true; 299 m_terrainModified = true;
302 }); 300 }
303 } 301 }
304 } 302 }
305 303
@@ -308,9 +306,9 @@ public sealed class BSTerrainManager
308 { 306 {
309 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 307 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
310 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 308 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
311 (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); 309 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
312 BSTerrainPhys newTerrainPhys = null; 310 BSTerrainPhys newTerrainPhys = null;
313 switch ((int)PhysicsScene.Params.terrainImplementation) 311 switch ((int)BSParam.TerrainImplementation)
314 { 312 {
315 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 313 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
316 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 314 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
@@ -323,14 +321,21 @@ public sealed class BSTerrainManager
323 default: 321 default:
324 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 322 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
325 LogHeader, 323 LogHeader,
326 (int)PhysicsScene.Params.terrainImplementation, 324 (int)BSParam.TerrainImplementation,
327 PhysicsScene.Params.terrainImplementation, 325 BSParam.TerrainImplementation,
328 PhysicsScene.RegionName, terrainRegionBase); 326 PhysicsScene.RegionName, terrainRegionBase);
329 break; 327 break;
330 } 328 }
331 return newTerrainPhys; 329 return newTerrainPhys;
332 } 330 }
333 331
332 // Return 'true' of this position is somewhere in known physical terrain space
333 public bool IsWithinKnownTerrain(Vector3 pos)
334 {
335 Vector3 terrainBaseXYZ;
336 BSTerrainPhys physTerrain;
337 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
338 }
334 339
335 // Given an X and Y, find the height of the terrain. 340 // Given an X and Y, find the height of the terrain.
336 // Since we could be handling multiple terrains for a mega-region, 341 // Since we could be handling multiple terrains for a mega-region,
@@ -341,40 +346,74 @@ public sealed class BSTerrainManager
341 private float lastHeightTX = 999999f; 346 private float lastHeightTX = 999999f;
342 private float lastHeightTY = 999999f; 347 private float lastHeightTY = 999999f;
343 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 348 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
344 public float GetTerrainHeightAtXYZ(Vector3 loc) 349 public float GetTerrainHeightAtXYZ(Vector3 pos)
345 { 350 {
346 float tX = loc.X; 351 float tX = pos.X;
347 float tY = loc.Y; 352 float tY = pos.Y;
348 // You'd be surprized at the number of times this routine is called 353 // You'd be surprized at the number of times this routine is called
349 // with the same parameters as last time. 354 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 355 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
351 return lastHeight; 356 return lastHeight;
357 m_terrainModified = false;
352 358
353 lastHeightTX = tX; 359 lastHeightTX = tX;
354 lastHeightTY = tY; 360 lastHeightTY = tY;
355 float ret = HEIGHT_GETHEIGHT_RET; 361 float ret = HEIGHT_GETHEIGHT_RET;
356 362
357 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 363 Vector3 terrainBaseXYZ;
358 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
359 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
360
361 BSTerrainPhys physTerrain; 364 BSTerrainPhys physTerrain;
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) 365 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
363 { 366 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 367 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
367 } 368 }
368 else 369 else
369 { 370 {
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 371 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
371 LogHeader, PhysicsScene.RegionName, tX, tY); 372 LogHeader, PhysicsScene.RegionName, tX, tY);
373 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
374 BSScene.DetailLogZero, pos, terrainBaseXYZ);
372 } 375 }
373 m_terrainModified = false; 376
374 lastHeight = ret; 377 lastHeight = ret;
375 return ret; 378 return ret;
376 } 379 }
377 380
381 public float GetWaterLevelAtXYZ(Vector3 pos)
382 {
383 float ret = WATER_HEIGHT_GETHEIGHT_RET;
384
385 Vector3 terrainBaseXYZ;
386 BSTerrainPhys physTerrain;
387 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
388 {
389 ret = physTerrain.GetWaterLevelAtXYZ(pos);
390 }
391 else
392 {
393 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
394 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
395 }
396 return ret;
397 }
398
399 // Given an address, return 'true' of there is a description of that terrain and output
400 // the descriptor class and the 'base' fo the addresses therein.
401 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
402 {
403 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
404 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
405 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
406
407 BSTerrainPhys physTerrain = null;
408 lock (m_terrains)
409 {
410 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
411 }
412 outTerrainBase = terrainBaseXYZ;
413 outPhysTerrain = physTerrain;
414 return (physTerrain != null);
415 }
416
378 // Although no one seems to check this, I do support combining. 417 // Although no one seems to check this, I do support combining.
379 public bool SupportsCombining() 418 public bool SupportsCombining()
380 { 419 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150..8244f02 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -88,11 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 // Something is very messed up and a crash is in our future. 88 // Something is very messed up and a crash is in our future.
89 return; 89 return;
90 } 90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
91 93
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 94 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
93 indicesCount, indices, verticesCount, vertices), 95 if (!m_terrainShape.HasPhysicalShape)
94 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero)
96 { 96 {
97 // DISASTER!! 97 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); 98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
@@ -104,8 +104,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
104 Vector3 pos = regionBase; 104 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity; 105 Quaternion rot = Quaternion.Identity;
106 106
107 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); 107 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
108 if (m_terrainBody.ptr == IntPtr.Zero) 108 if (!m_terrainBody.HasPhysicalBody)
109 { 109 {
110 // DISASTER!! 110 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
@@ -114,39 +114,40 @@ public sealed class BSTerrainMesh : BSTerrainPhys
114 } 114 }
115 115
116 // Set current terrain attributes 116 // Set current terrain attributes
117 BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); 117 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
118 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); 118 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
119 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 119 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
120 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 120 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
121 121
122 // Static objects are not very massive. 122 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 123 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
124 124
125 // Return the new terrain to the world of physical objects 125 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 126 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);
127 127
128 // redo its bounding box now that it is in the world 128 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 129 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);
130 130
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 131 m_terrainBody.collisionType = CollisionType.Terrain;
132 (uint)CollisionFilterGroups.TerrainFilter, 132 m_terrainBody.ApplyCollisionMask(PhysicsScene);
133 (uint)CollisionFilterGroups.TerrainMask);
134 133
135 // Make it so the terrain will not move or be considered for movement. 134 // Make it so the terrain will not move or be considered for movement.
136 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 135 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
137 } 136 }
138 137
139 public override void Dispose() 138 public override void Dispose()
140 { 139 {
141 if (m_terrainBody.ptr != IntPtr.Zero) 140 if (m_terrainBody.HasPhysicalBody)
142 { 141 {
143 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 142 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody);
144 // Frees both the body and the shape. 143 // Frees both the body and the shape.
145 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); 144 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody);
145 m_terrainBody.Clear();
146 m_terrainShape.Clear();
146 } 147 }
147 } 148 }
148 149
149 public override float GetHeightAtXYZ(Vector3 pos) 150 public override float GetTerrainHeightAtXYZ(Vector3 pos)
150 { 151 {
151 // For the moment use the saved heightmap to get the terrain height. 152 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position. 153 // TODO: raycast downward to find the true terrain below the position.
@@ -167,6 +168,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
167 return ret; 168 return ret;
168 } 169 }
169 170
171 // The passed position is relative to the base of the region.
172 public override float GetWaterLevelAtXYZ(Vector3 pos)
173 {
174 return PhysicsScene.SimpleWaterLevel;
175 }
176
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 177 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created. 178 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh( 179 public static bool ConvertHeightmapToMesh(
@@ -188,6 +195,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
188 // Simple mesh creation which assumes magnification == 1. 195 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result. 196 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190 197
198 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
199 // from zero to <= sizeX). The triangle indices are then generated as two triangles
200 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
201 // column of vertices are used to complete the triangles of the last row and column
202 // of the heightmap.
191 try 203 try
192 { 204 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge. 205 // One vertice per heightmap value plus the vertices off the top and bottom edge.
@@ -200,16 +212,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
200 float magY = (float)sizeY / extentY; 212 float magY = (float)sizeY / extentY;
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 213 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 214 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
215 float minHeight = float.MaxValue;
203 // Note that sizeX+1 vertices are created since there is land between this and the next region. 216 // 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++) 217 for (int yy = 0; yy <= sizeY; yy++)
205 { 218 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times 219 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
207 { 220 {
208 int offset = yy * sizeX + xx; 221 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column 222 // Extend the height with the height from the last row or column
210 if (yy == sizeY) offset -= sizeX; 223 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1; 224 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset]; 225 float height = heightMap[offset];
226 minHeight = Math.Min(minHeight, height);
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 227 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 228 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z; 229 vertices[verticesCount + 2] = height + extentBase.Z;
@@ -217,14 +231,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
217 } 231 }
218 } 232 }
219 verticesCount = verticesCount / 3; 233 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222 234
223 for (int yy = 0; yy < sizeY; yy++) 235 for (int yy = 0; yy < sizeY; yy++)
224 { 236 {
225 for (int xx = 0; xx < sizeX; xx++) 237 for (int xx = 0; xx < sizeX; xx++)
226 { 238 {
227 int offset = yy * sizeX + xx; 239 int offset = yy * (sizeX + 1) + xx;
228 // Each vertices is presumed to be the upper left corner of a box of two triangles 240 // Each vertices is presumed to be the upper left corner of a box of two triangles
229 indices[indicesCount + 0] = offset; 241 indices[indicesCount + 0] = offset;
230 indices[indicesCount + 1] = offset + 1; 242 indices[indicesCount + 1] = offset + 1;
@@ -235,8 +247,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
235 indicesCount += 6; 247 indicesCount += 6;
236 } 248 }
237 } 249 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG 250
239 LogHeader, indicesCount); // DEBUG
240 ret = true; 251 ret = true;
241 } 252 }
242 catch (Exception e) 253 catch (Exception e)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
deleted file mode 100644
index e60a760..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ /dev/null
@@ -1,1015 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Runtime.InteropServices;
29using System.Security;
30using System.Text;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin {
34
35// Classes to allow some type checking for the API
36// These hold pointers to allocated objects in the unmanaged space.
37
38// The physics engine controller class created at initialization
39public struct BulletSim
40{
41 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
42 {
43 ptr = xx;
44 worldID = worldId;
45 physicsScene = bss;
46 }
47 public IntPtr ptr;
48 public uint worldID;
49 // The scene is only in here so very low level routines have a handle to print debug/error messages
50 public BSScene physicsScene;
51}
52
53// An allocated Bullet btRigidBody
54public struct BulletBody
55{
56 public BulletBody(uint id, IntPtr xx)
57 {
58 ID = id;
59 ptr = xx;
60 collisionFilter = 0;
61 collisionMask = 0;
62 }
63 public IntPtr ptr;
64 public uint ID;
65 public CollisionFilterGroups collisionFilter;
66 public CollisionFilterGroups collisionMask;
67 public override string ToString()
68 {
69 StringBuilder buff = new StringBuilder();
70 buff.Append("<id=");
71 buff.Append(ID.ToString());
72 buff.Append(",p=");
73 buff.Append(ptr.ToString("X"));
74 if (collisionFilter != 0 || collisionMask != 0)
75 {
76 buff.Append(",f=");
77 buff.Append(collisionFilter.ToString("X"));
78 buff.Append(",m=");
79 buff.Append(collisionMask.ToString("X"));
80 }
81 buff.Append(">");
82 return buff.ToString();
83 }
84}
85
86public struct BulletShape
87{
88 public BulletShape(IntPtr xx)
89 {
90 ptr = xx;
91 type=BSPhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public BSPhysicsShapeType type;
104 public System.UInt64 shapeKey;
105 public bool isNativeShape;
106 public override string ToString()
107 {
108 StringBuilder buff = new StringBuilder();
109 buff.Append("<p=");
110 buff.Append(ptr.ToString("X"));
111 buff.Append(",s=");
112 buff.Append(type.ToString());
113 buff.Append(",k=");
114 buff.Append(shapeKey.ToString("X"));
115 buff.Append(",n=");
116 buff.Append(isNativeShape.ToString());
117 buff.Append(">");
118 return buff.ToString();
119 }
120}
121
122 // Constraint type values as defined by Bullet
123public enum ConstraintType : int
124{
125 POINT2POINT_CONSTRAINT_TYPE = 3,
126 HINGE_CONSTRAINT_TYPE,
127 CONETWIST_CONSTRAINT_TYPE,
128 D6_CONSTRAINT_TYPE,
129 SLIDER_CONSTRAINT_TYPE,
130 CONTACT_CONSTRAINT_TYPE,
131 D6_SPRING_CONSTRAINT_TYPE,
132 MAX_CONSTRAINT_TYPE
133}
134
135// An allocated Bullet btConstraint
136public struct BulletConstraint
137{
138 public BulletConstraint(IntPtr xx)
139 {
140 ptr = xx;
141 }
142 public IntPtr ptr;
143}
144
145// An allocated HeightMapThing which holds various heightmap info.
146// Made a class rather than a struct so there would be only one
147// instance of this and C# will pass around pointers rather
148// than making copies.
149public class BulletHeightMapInfo
150{
151 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
152 ID = id;
153 Ptr = xx;
154 heightMap = hm;
155 terrainRegionBase = Vector3.Zero;
156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f;
159 sizeX = sizeY = 256f;
160 }
161 public uint ID;
162 public IntPtr Ptr;
163 public float[] heightMap;
164 public Vector3 terrainRegionBase;
165 public Vector3 minCoords;
166 public Vector3 maxCoords;
167 public float sizeX, sizeY;
168 public float minZ, maxZ;
169 public BulletShape terrainShape;
170 public BulletBody terrainBody;
171}
172
173// ===============================================================================
174[StructLayout(LayoutKind.Sequential)]
175public struct ConvexHull
176{
177 Vector3 Offset;
178 int VertexCount;
179 Vector3[] Vertices;
180}
181public enum BSPhysicsShapeType
182{
183 SHAPE_UNKNOWN = 0,
184 SHAPE_CAPSULE = 1,
185 SHAPE_BOX = 2,
186 SHAPE_CONE = 3,
187 SHAPE_CYLINDER = 4,
188 SHAPE_SPHERE = 5,
189 SHAPE_MESH = 6,
190 SHAPE_HULL = 7,
191 // following defined by BulletSim
192 SHAPE_GROUNDPLANE = 20,
193 SHAPE_TERRAIN = 21,
194 SHAPE_COMPOUND = 22,
195 SHAPE_HEIGHTMAP = 23,
196};
197
198// The native shapes have predefined shape hash keys
199public enum FixedShapeKey : ulong
200{
201 KEY_NONE = 0,
202 KEY_BOX = 1,
203 KEY_SPHERE = 2,
204 KEY_CONE = 3,
205 KEY_CYLINDER = 4,
206 KEY_CAPSULE = 5,
207}
208
209[StructLayout(LayoutKind.Sequential)]
210public struct ShapeData
211{
212 public uint ID;
213 public BSPhysicsShapeType Type;
214 public Vector3 Position;
215 public Quaternion Rotation;
216 public Vector3 Velocity;
217 public Vector3 Scale;
218 public float Mass;
219 public float Buoyancy;
220 public System.UInt64 HullKey;
221 public System.UInt64 MeshKey;
222 public float Friction;
223 public float Restitution;
224 public float Collidable; // true of things bump into this
225 public float Static; // true if a static object. Otherwise gravity, etc.
226 public float Solid; // true if object cannot be passed through
227 public Vector3 Size;
228
229 // note that bools are passed as floats since bool size changes by language and architecture
230 public const float numericTrue = 1f;
231 public const float numericFalse = 0f;
232}
233[StructLayout(LayoutKind.Sequential)]
234public struct SweepHit
235{
236 public uint ID;
237 public float Fraction;
238 public Vector3 Normal;
239 public Vector3 Point;
240}
241[StructLayout(LayoutKind.Sequential)]
242public struct RaycastHit
243{
244 public uint ID;
245 public float Fraction;
246 public Vector3 Normal;
247}
248[StructLayout(LayoutKind.Sequential)]
249public struct CollisionDesc
250{
251 public uint aID;
252 public uint bID;
253 public Vector3 point;
254 public Vector3 normal;
255}
256[StructLayout(LayoutKind.Sequential)]
257public struct EntityProperties
258{
259 public uint ID;
260 public Vector3 Position;
261 public Quaternion Rotation;
262 public Vector3 Velocity;
263 public Vector3 Acceleration;
264 public Vector3 RotationalVelocity;
265}
266
267// Format of this structure must match the definition in the C++ code
268[StructLayout(LayoutKind.Sequential)]
269public struct ConfigurationParameters
270{
271 public float defaultFriction;
272 public float defaultDensity;
273 public float defaultRestitution;
274 public float collisionMargin;
275 public float gravity;
276
277 public float linearDamping;
278 public float angularDamping;
279 public float deactivationTime;
280 public float linearSleepingThreshold;
281 public float angularSleepingThreshold;
282 public float ccdMotionThreshold;
283 public float ccdSweptSphereRadius;
284 public float contactProcessingThreshold;
285
286 public float terrainImplementation;
287 public float terrainFriction;
288 public float terrainHitFraction;
289 public float terrainRestitution;
290 public float avatarFriction;
291 public float avatarStandingFriction;
292 public float avatarDensity;
293 public float avatarRestitution;
294 public float avatarCapsuleWidth;
295 public float avatarCapsuleDepth;
296 public float avatarCapsuleHeight;
297 public float avatarContactProcessingThreshold;
298
299 public float maxPersistantManifoldPoolSize;
300 public float maxCollisionAlgorithmPoolSize;
301 public float shouldDisableContactPoolDynamicAllocation;
302 public float shouldForceUpdateAllAabbs;
303 public float shouldRandomizeSolverOrder;
304 public float shouldSplitSimulationIslands;
305 public float shouldEnableFrictionCaching;
306 public float numberOfSolverIterations;
307
308 public float linksetImplementation;
309 public float linkConstraintUseFrameOffset;
310 public float linkConstraintEnableTransMotor;
311 public float linkConstraintTransMotorMaxVel;
312 public float linkConstraintTransMotorMaxForce;
313 public float linkConstraintERP;
314 public float linkConstraintCFM;
315 public float linkConstraintSolverIterations;
316
317 public float physicsLoggingFrames;
318
319 public const float numericTrue = 1f;
320 public const float numericFalse = 0f;
321}
322
323
324// The states a bullet collision object can have
325public enum ActivationState : uint
326{
327 ACTIVE_TAG = 1,
328 ISLAND_SLEEPING,
329 WANTS_DEACTIVATION,
330 DISABLE_DEACTIVATION,
331 DISABLE_SIMULATION,
332}
333
334public enum CollisionObjectTypes : int
335{
336 CO_COLLISION_OBJECT = 1 << 0,
337 CO_RIGID_BODY = 1 << 1,
338 CO_GHOST_OBJECT = 1 << 2,
339 CO_SOFT_BODY = 1 << 3,
340 CO_HF_FLUID = 1 << 4,
341 CO_USER_TYPE = 1 << 5,
342}
343
344// Values used by Bullet and BulletSim to control object properties.
345// Bullet's "CollisionFlags" has more to do with operations on the
346// object (if collisions happen, if gravity effects it, ...).
347public enum CollisionFlags : uint
348{
349 CF_STATIC_OBJECT = 1 << 0,
350 CF_KINEMATIC_OBJECT = 1 << 1,
351 CF_NO_CONTACT_RESPONSE = 1 << 2,
352 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
353 CF_CHARACTER_OBJECT = 1 << 4,
354 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
355 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
356 // Following used by BulletSim to control collisions
357 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
358 BS_FLOATS_ON_WATER = 1 << 11,
359 BS_NONE = 0,
360 BS_ALL = 0xFFFFFFFF,
361
362 // These are the collision flags switched depending on physical state.
363 // The other flags are used for other things and should not be fooled with.
364 BS_ACTIVE = CF_STATIC_OBJECT
365 | CF_KINEMATIC_OBJECT
366 | CF_NO_CONTACT_RESPONSE
367};
368
369// Values for collisions groups and masks
370public enum CollisionFilterGroups : uint
371{
372 // Don't use the bit definitions!! Define the use in a
373 // filter/mask definition below. This way collision interactions
374 // are more easily debugged.
375 BNoneFilter = 0,
376 BDefaultFilter = 1 << 0,
377 BStaticFilter = 1 << 1,
378 BKinematicFilter = 1 << 2,
379 BDebrisFilter = 1 << 3,
380 BSensorTrigger = 1 << 4,
381 BCharacterFilter = 1 << 5,
382 BAllFilter = 0xFFFFFFFF,
383 // Filter groups defined by BulletSim
384 BGroundPlaneFilter = 1 << 10,
385 BTerrainFilter = 1 << 11,
386 BRaycastFilter = 1 << 12,
387 BSolidFilter = 1 << 13,
388 BLinksetFilter = 1 << 14,
389
390 // The collsion filters and masked are defined in one place -- don't want them scattered
391 AvatarFilter = BCharacterFilter,
392 AvatarMask = BAllFilter,
393 ObjectFilter = BSolidFilter,
394 ObjectMask = BAllFilter,
395 StaticObjectFilter = BStaticFilter,
396 StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other
397 LinksetFilter = BLinksetFilter,
398 LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other
399 VolumeDetectFilter = BSensorTrigger,
400 VolumeDetectMask = ~BSensorTrigger,
401 TerrainFilter = BTerrainFilter,
402 TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide
403 GroundPlaneFilter = BGroundPlaneFilter,
404 GroundPlaneMask = BAllFilter
405
406};
407
408// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
409// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
410public enum ConstraintParams : int
411{
412 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
413 BT_CONSTRAINT_STOP_ERP,
414 BT_CONSTRAINT_CFM,
415 BT_CONSTRAINT_STOP_CFM,
416};
417public enum ConstraintParamAxis : int
418{
419 AXIS_LINEAR_X = 0,
420 AXIS_LINEAR_Y,
421 AXIS_LINEAR_Z,
422 AXIS_ANGULAR_X,
423 AXIS_ANGULAR_Y,
424 AXIS_ANGULAR_Z,
425 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
426 AXIS_ANGULAR_ALL,
427 AXIS_ALL
428};
429
430// ===============================================================================
431static class BulletSimAPI {
432
433// Link back to the managed code for outputting log messages
434[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
435public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
436
437// ===============================================================================
438// Initialization and simulation
439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
440public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
441 int maxCollisions, IntPtr collisionArray,
442 int maxUpdates, IntPtr updateArray,
443 DebugLogCallback logRoutine);
444
445[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
446public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
447
448[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
449public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
450
451[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
452public static extern void Shutdown2(IntPtr sim);
453
454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
455public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
456 out int updatedEntityCount,
457 out IntPtr updatedEntitiesPtr,
458 out int collidersCount,
459 out IntPtr collidersPtr);
460
461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
462public static extern bool PushUpdate2(IntPtr obj);
463
464// =====================================================================================
465// Mesh, hull, shape and body creation helper routines
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern IntPtr CreateMeshShape2(IntPtr world,
468 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
469 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
470
471[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
472public static extern IntPtr CreateHullShape2(IntPtr world,
473 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
474
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
477
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
480
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool IsNativeShape2(IntPtr shape);
483
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
486
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
489
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
492
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
495
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
498
499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
500public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
501
502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
503public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
504
505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
506public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
507
508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
509public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
510
511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
512public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
513
514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
515public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
516
517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
518public static extern int GetBodyType2(IntPtr obj);
519
520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
521public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
522
523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
524public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
525
526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
527public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
528
529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
530public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
531
532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
533public static extern void ReleaseBodyInfo2(IntPtr obj);
534
535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
536public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
537
538// =====================================================================================
539// Terrain creation and helper routines
540[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
541public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
542 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
543
544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
545public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
546 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
547
548[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
549public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
550
551[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
552public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
553
554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
555public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
556
557// =====================================================================================
558// Constraint creation and helper routines
559[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
560public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
561 Vector3 frame1loc, Quaternion frame1rot,
562 Vector3 frame2loc, Quaternion frame2rot,
563 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
564
565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
566public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
567 Vector3 joinPoint,
568 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
569
570[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
571public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
572 Vector3 pivotinA, Vector3 pivotinB,
573 Vector3 axisInA, Vector3 axisInB,
574 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
575
576[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
577public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
578
579[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
580public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
581
582[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
583public static extern bool SetFrames2(IntPtr constrain,
584 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
585
586[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
587public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
588
589[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
590public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
591
592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
593public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
594
595[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
596public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
597
598[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
599public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
600
601[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
602public static extern bool CalculateTransforms2(IntPtr constrain);
603
604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
605public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
606
607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
608public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
609
610// =====================================================================================
611// btCollisionWorld entries
612[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
613public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
614
615[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
616public static extern void UpdateAabbs2(IntPtr world);
617
618[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
619public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
620
621[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
622public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
623
624// =====================================================================================
625// btDynamicsWorld entries
626[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
627public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
628
629[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
630public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
631
632[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
633public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
634
635[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
636public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
637// =====================================================================================
638// btCollisionObject entries
639[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
640public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
641
642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
643public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
644
645[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
646public static extern bool HasAnisotripicFriction2(IntPtr constrain);
647
648[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
649public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
650
651[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
652public static extern float GetContactProcessingThreshold2(IntPtr obj);
653
654[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
655public static extern bool IsStaticObject2(IntPtr obj);
656
657[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
658public static extern bool IsKinematicObject2(IntPtr obj);
659
660[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
661public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
662
663[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
664public static extern bool HasContactResponse2(IntPtr obj);
665
666[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
667public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
668
669[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
670public static extern IntPtr GetCollisionShape2(IntPtr obj);
671
672[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
673public static extern int GetActivationState2(IntPtr obj);
674
675[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
676public static extern void SetActivationState2(IntPtr obj, int state);
677
678[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
679public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
680
681[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
682public static extern float GetDeactivationTime2(IntPtr obj);
683
684[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
685public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
686
687[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
688public static extern void Activate2(IntPtr obj, bool forceActivation);
689
690[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
691public static extern bool IsActive2(IntPtr obj);
692
693[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
694public static extern void SetRestitution2(IntPtr obj, float val);
695
696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
697public static extern float GetRestitution2(IntPtr obj);
698
699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
700public static extern void SetFriction2(IntPtr obj, float val);
701
702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
703public static extern float GetFriction2(IntPtr obj);
704
705 /* Haven't defined the type 'Transform'
706[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
707public static extern Transform GetWorldTransform2(IntPtr obj);
708
709[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
710public static extern void setWorldTransform2(IntPtr obj, Transform trans);
711 */
712
713[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
714public static extern Vector3 GetPosition2(IntPtr obj);
715
716[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
717public static extern Quaternion GetOrientation2(IntPtr obj);
718
719[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
720public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
721
722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
723public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
724
725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
726public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
727
728 /*
729[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
730public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
731
732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
733public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
734 */
735
736[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
737public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
738
739[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
740public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
741
742[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
743public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
744
745[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
746public static extern float GetHitFraction2(IntPtr obj);
747
748[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
749public static extern void SetHitFraction2(IntPtr obj, float val);
750
751[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
752public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
753
754[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
755public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
756
757[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
758public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
759
760[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
761public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
762
763[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
764public static extern float GetCcdMotionThreshold2(IntPtr obj);
765
766[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
767public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
768
769[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
770public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
771
772[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
773public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
774
775[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
776public static extern IntPtr GetUserPointer2(IntPtr obj);
777
778[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
779public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
780
781// =====================================================================================
782// btRigidBody entries
783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
784public static extern void ApplyGravity2(IntPtr obj);
785
786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
787public static extern void SetGravity2(IntPtr obj, Vector3 val);
788
789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
790public static extern Vector3 GetGravity2(IntPtr obj);
791
792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
793public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
794
795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
796public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
797
798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
799public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
800
801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
802public static extern float GetLinearDamping2(IntPtr obj);
803
804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
805public static extern float GetAngularDamping2(IntPtr obj);
806
807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
808public static extern float GetLinearSleepingThreshold2(IntPtr obj);
809
810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
811public static extern float GetAngularSleepingThreshold2(IntPtr obj);
812
813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
814public static extern void ApplyDamping2(IntPtr obj, float timeStep);
815
816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
817public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
818
819[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
820public static extern Vector3 GetLinearFactor2(IntPtr obj);
821
822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
823public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
824
825 /*
826[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
827public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
828 */
829
830[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
831public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
832
833// Add a force to the object as if its mass is one.
834[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
835public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
836
837// Set the force being applied to the object as if its mass is one.
838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
839public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
840
841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
842public static extern Vector3 GetTotalForce2(IntPtr obj);
843
844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
845public static extern Vector3 GetTotalTorque2(IntPtr obj);
846
847[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
848public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
849
850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
851public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
852
853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
854public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
855
856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
857public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
858
859// Apply force at the given point. Will add torque to the object.
860[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
861public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
862
863// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
864[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
865public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
866
867// Apply impulse to the object's torque. Force is scaled by object's mass.
868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
869public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
870
871// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
872[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
873public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
874
875[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
876public static extern void ClearForces2(IntPtr obj);
877
878[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
879public static extern void ClearAllForces2(IntPtr obj);
880
881[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
882public static extern void UpdateInertiaTensor2(IntPtr obj);
883
884[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
885public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
886
887 /*
888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
889public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
890 */
891
892[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
893public static extern Vector3 GetLinearVelocity2(IntPtr obj);
894
895[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
896public static extern Vector3 GetAngularVelocity2(IntPtr obj);
897
898[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
899public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
900
901[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
902public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
903
904[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
905public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
906
907[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
908public static extern void Translate2(IntPtr obj, Vector3 trans);
909
910[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
911public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
912
913[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
914public static extern bool WantsSleeping2(IntPtr obj);
915
916[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
917public static extern void SetAngularFactor2(IntPtr obj, float factor);
918
919[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
920public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
921
922[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
923public static extern Vector3 GetAngularFactor2(IntPtr obj);
924
925[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
926public static extern bool IsInWorld2(IntPtr obj);
927
928[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
929public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
930
931[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
932public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
933
934[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
935public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
936
937[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
938public static extern int GetNumConstraintRefs2(IntPtr obj);
939
940[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
941public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
942
943// =====================================================================================
944// btCollisionShape entries
945
946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
947public static extern float GetAngularMotionDisc2(IntPtr shape);
948
949[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
950public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
951
952[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
953public static extern bool IsPolyhedral2(IntPtr shape);
954
955[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
956public static extern bool IsConvex2d2(IntPtr shape);
957
958[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
959public static extern bool IsConvex2(IntPtr shape);
960
961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
962public static extern bool IsNonMoving2(IntPtr shape);
963
964[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
965public static extern bool IsConcave2(IntPtr shape);
966
967[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
968public static extern bool IsCompound2(IntPtr shape);
969
970[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
971public static extern bool IsSoftBody2(IntPtr shape);
972
973[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
974public static extern bool IsInfinite2(IntPtr shape);
975
976[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
977public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
978
979[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
980public static extern Vector3 GetLocalScaling2(IntPtr shape);
981
982[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
983public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
984
985[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
986public static extern int GetShapeType2(IntPtr shape);
987
988[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
989public static extern void SetMargin2(IntPtr shape, float val);
990
991[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
992public static extern float GetMargin2(IntPtr shape);
993
994// =====================================================================================
995// Debugging
996[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
997public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
998
999[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1000public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1001
1002[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1003public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1004
1005[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1006public static extern void DumpAllInfo2(IntPtr sim);
1007
1008[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1009public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1010
1011[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1012public static extern void DumpPhysicsStatistics2(IntPtr sim);
1013
1014}
1015}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
new file mode 100755
index 0000000..c7a2f7e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -0,0 +1,265 @@
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// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
221// but, instead, use references to this dictionary. Finding and debugging
222// collision flag problems will be made easier.
223public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
224 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
225{
226 { CollisionType.Avatar,
227 new CollisionTypeFilterGroup(CollisionType.Avatar,
228 (uint)CollisionFilterGroups.BCharacterGroup,
229 (uint)CollisionFilterGroups.BAllGroup)
230 },
231 { CollisionType.Groundplane,
232 new CollisionTypeFilterGroup(CollisionType.Groundplane,
233 (uint)CollisionFilterGroups.BGroundPlaneGroup,
234 (uint)CollisionFilterGroups.BAllGroup)
235 },
236 { CollisionType.Terrain,
237 new CollisionTypeFilterGroup(CollisionType.Terrain,
238 (uint)CollisionFilterGroups.BTerrainGroup,
239 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
240 },
241 { CollisionType.Static,
242 new CollisionTypeFilterGroup(CollisionType.Static,
243 (uint)CollisionFilterGroups.BStaticGroup,
244 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
245 },
246 { CollisionType.Dynamic,
247 new CollisionTypeFilterGroup(CollisionType.Dynamic,
248 (uint)CollisionFilterGroups.BSolidGroup,
249 (uint)(CollisionFilterGroups.BAllGroup))
250 },
251 { CollisionType.VolumeDetect,
252 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
253 (uint)CollisionFilterGroups.BSensorTrigger,
254 (uint)(~CollisionFilterGroups.BSensorTrigger))
255 },
256 { CollisionType.LinksetChild,
257 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
258 (uint)CollisionFilterGroups.BLinksetChildGroup,
259 (uint)(CollisionFilterGroups.BNoneGroup))
260 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
261 },
262};
263
264}
265}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
new file mode 100755
index 0000000..801f690
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -0,0 +1,324 @@
1CURRENT PRIORITIES
2=================================================
3Deleting a linkset while standing on the root will leave the physical shape of the root behind.
4 Not sure if it is because standing on it. Done with large prim linksets.
5Child movement in linkset (don't rebuild linkset)
6Vehicle angular vertical attraction
7vehicle angular banking
8Center-of-gravity
9Vehicle angular deflection
10 Preferred orientation angular correction fix
11when should angular and linear motor targets be zeroed? when selected?
12 Need a vehicle.clear()? Or an 'else' in prestep if not physical.
13Teravus llMoveToTarget script debug
14 Mixing of hover, buoyancy/gravity, moveToTarget, into one force
15Nebadon vehicles turning funny in arena
16limitMotorUp calibration (more down?)
17llRotLookAt
18llLookAt
19Avatars walking up stairs (HALF DONE)
20Avatar movement
21 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
22 walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
23 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
24Enable vehicle border crossings (at least as poorly as ODE)
25 Terrain skirts
26 Avatar created in previous region and not new region when crossing border
27 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
28Vehicle script tuning/debugging
29 Avanti speed script
30 Weapon shooter script
31Add material densities to the material types
32
33CRASHES
34=================================================
35Crazyness during 20130115 office hours was PositionAdjustUnderground for both char and prim
36 m1:logs/20130115.0934/physics-BulletSim-20130115083613.log
37 Creation of Neb's terrain made the terrain "disappear". Everything started to fall
38 and then get restored to be above terrain.
3920121129.1411: editting/moving phys object across region boundries causes crash
40 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
4120121128.1600: mesh object not rezzing (no physics mesh).
42 Causes many errors. Doesn't stop after first error with box shape.
43 Eventually crashes when deleting the object.
4420121206.1434: rez Sam-pan into OSGrid BulletSim11 region
45 Immediate simulator crash. Mono does not output any stacktrace and
46 log just stops after reporting taint-time linking of the linkset.
47
48VEHICLES TODO LIST:
49=================================================
50Border crossing with linked vehicle causes crash
51Vehicles (Move smoothly)
52Some vehicles should not be able to turn if no speed or off ground.
53Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
54Neb car jiggling left and right
55 Happens on terrain and any other mesh object. Flat cubes are much smoother.
56 This has been reduced but not eliminated.
57Implement referenceFrame for all the motion routines.
58For limitMotorUp, use raycast down to find if vehicle is in the air.
59Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
60 Verify that angular motion specified around Z moves in the vehicle coordinates.
61Verify llGetVel() is returning a smooth and good value for vehicle movement.
62llGetVel() should return the root's velocity if requested in a child prim.
63Implement function efficiency for lineaar and angular motion.
64After getting off a vehicle, the root prim is phantom (can be walked through)
65 Need to force a position update for the root prim after compound shape destruction
66Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
67Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
68 A kludge that isn't fixing the real problem of Bullet adding extra motion.
69Incorporate inter-relationship of angular corrections. For instance, angularDeflection
70 and angularMotorUp will compute same X or Y correction. When added together
71 creates over-correction and over-shoot and wabbling.
72
73GENERAL TODO LIST:
74=================================================
75llMoveToTarget objects are not effected by gravity until target is removed.
76Implement llSetPhysicalMaterial.
77 extend it with Center-of-mass, rolling friction, density
78Implement llSetForceAndTorque.
79Change BSPrim.moveToTarget to used forces rather than changing position
80 Changing position allows one to move through walls
81Implement an avatar mesh shape. The Bullet capsule is way too limited.
82 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
83Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
84Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
85Duplicating a physical prim causes old prim to jump away
86 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
87Scenes with hundred of thousands of static objects take a lot of physics CPU time.
88BSPrim.Force should set a continious force on the prim. The force should be
89 applied each tick. Some limits?
90Gun sending shooter flying.
91Collision margin (gap between physical objects lying on each other)
92Boundry checking (crashes related to crossing boundry)
93 Add check for border edge position for avatars and objects.
94 Verify the events are created for border crossings.
95Avatar rotation (check out changes to ScenePresence for physical rotation)
96Avatar running (what does phys engine need to do?)
97Small physical objects do not interact correctly
98 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
99 The chain will fall apart and pairs will dance around on ground
100 Chains of 1x1x.2 will stay connected but will dance.
101 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
102Add PID motor for avatar movement (slow to stop, ...)
103setForce should set a constant force. Different than AddImpulse.
104Implement raycast.
105Implement ShapeCollection.Dispose()
106Implement water as a plain so raycasting and collisions can happen with same.
107Add collision penetration return
108 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
109Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
110 Also osGetPhysicsEngineVerion() maybe.
111Linkset.Position and Linkset.Orientation requre rewrite to properly return
112 child position. LinksetConstraint acts like it's at taint time!!
113Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
114Should the different PID factors have non-equal contributions for different
115 values of Efficiency?
116Selecting and deselecting physical objects causes CPU processing time to jump
117 http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1
118 put thousand physical objects, select and deselect same. CPU time will be large.
119Re-implement buoyancy as a separate force on the object rather than diddling gravity.
120 Register a pre-step event to add the force.
121More efficient memory usage when passing hull information from BSPrim to BulletSim
122Avatar movement motor check for zero or small movement. Somehow suppress small movements
123 when avatar has stopped and is just standing. Simple test for near zero has
124 the problem of preventing starting up (increase from zero) especially when falling.
125Physical and phantom will drop through the terrain
126
127
128LINKSETS
129======================================================
130Editing a child of a linkset causes the child to go phantom
131 Move a child prim once when it is physical and can never move it again without it going phantom
132Offset the center of the linkset to be the geometric center of all the prims
133 Not quite the same as the center-of-gravity
134Linksets should allow collisions to individual children
135 Add LocalID to children shapes in LinksetCompound and create events for individuals
136LinksetCompound: when one of the children changes orientation (like tires
137 turning on a vehicle, the whole compound object is rebuilt. Optimize this
138 so orientation/position of individual children can change without a rebuild.
139Verify/think through scripts in children of linksets. What do they reference
140 and return when getting position, velocity, ...
141Confirm constraint linksets still work after making all the changes for compound linksets.
142Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding
143Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
144 For compound linksets, add ability to remove or reposition individual child shapes.
145Speed up creation of large physical linksets
146 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
147 REALLY bad for very large physical linksets (freezes the sim for many seconds).
148Eliminate collisions between objects in a linkset. (LinksetConstraint)
149 Have UserPointer point to struct with localID and linksetID?
150 Objects in original linkset still collide with each other?
151
152MORE
153======================================================
154Create tests for different interface components
155 Have test objects/scripts measure themselves and turn color if correct/bad
156 Test functions in SL and calibrate correctness there
157 Create auto rezzer and tracker to run through the tests
158Use the HACD convex hull routine in Bullet rather than the C# version.
159Do we need to do convex hulls all the time? Can complex meshes be left meshes?
160 There is some problem with meshes and collisions
161 Hulls are not as detailed as meshes. Hulled vehicles insides are different shape.
162Debounce avatar contact so legs don't keep folding up when standing.
163Implement LSL physics controls. Like STATUS_ROTATE_X.
164Add border extensions to terrain to help region crossings and objects leaving region.
165Use a different capsule shape for avatar when sitting
166 LL uses a pyrimidal shape scaled by the avatar's bounding box
167 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
168Performance test with lots of avatars. Can BulletSim support a thousand?
169Optimize collisions in C++: only send up to the object subscribed to collisions.
170 Use collision subscription and remove the collsion(A,B) and collision(B,A)
171Check whether SimMotionState needs large if statement (see TODO).
172Implement 'top colliders' info.
173Avatar jump
174Performance measurement and changes to make quicker.
175Implement detailed physics stats (GetStats()).
176Measure performance improvement from hulls
177Test not using ghost objects for volume detect implementation.
178Performance of closures and delegates for taint processing
179 Are there faster ways?
180 Is any slowdown introduced by the existing implementation significant?
181Is there are more efficient method of implementing pre and post step actions?
182 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
183Physics Arena central pyramid: why is one side permiable?
184In SL, perfect spheres don't seem to have rolling friction. Add special case.
185Enforce physical parameter min/max:
186 Gravity: [-1, 28]
187 Friction: [0, 255]
188 Density: [1, 22587]
189 Restitution [0, 1]
190 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
191Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
192Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html
193
194INTERNAL IMPROVEMENT/CLEANUP
195=================================================
196Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
197 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
198Create the physical wrapper classes (BulletBody, BulletShape) by methods on
199 BSAPITemplate and make their actual implementation Bullet engine specific.
200 For the short term, just call the existing functions in ShapeCollection.
201Consider moving prim/character body and shape destruction in destroy()
202 to postTimeTime rather than protecting all the potential sets that
203 might have been queued up.
204Remove unused fields from ShapeData (not used in API2)
205Remove unused fields from pinned memory shared parameter block
206 Create parameter variables in BSScene to replace same.
207Breakout code for mesh/hull/compound/native into separate BSShape* classes
208 Standardize access to building and reference code.
209 The skeleton classes are in the sources but are not complete or linked in.
210Make BSBody and BSShape real classes to centralize creation/changin/destruction
211 Convert state and parameter calls from BulletSimAPI direct calls to
212 calls on BSBody and BSShape
213Generalize Dynamics and PID with standardized motors.
214Generalize Linkset and vehicles into PropertyManagers
215 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
216 Potentially add events for shape destruction, etc.
217Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
218 BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc.
219Implement linkset by setting position of children when root updated. (LinksetManual)
220 Linkset implementation using manual prim movement.
221LinkablePrim class? Would that simplify/centralize the linkset logic?
222BSScene.UpdateParameterSet() is broken. How to set params on objects?
223Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
224 bob at the water level. BSPrim.PositionSanityCheck()
225Should taints check for existance or activeness of target?
226 When destroying linksets/etc, taints can be generated for objects that are
227 actually gone when the taint happens. Crashes don't happen because the taint closure
228 keeps the object from being freed, but that is just an accident.
229 Possibly have an 'active' flag that is checked by the taint processor?
230Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
231Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
232There are TOO MANY interfaces from BulletSim core to Bullet itself
233 Think of something to eliminate one or more of the layers
234
235THREADING
236=================================================
237Do taint action immediately if not actually executing Bullet.
238 Add lock around Bullet execution and just do taint actions if simulation is not happening.
239
240DONE DONE DONE DONE
241=================================================
242Cleanup code in BSDynamics by using motors. (Resolution: started)
243Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
244 Would have better and adjustable resolution.
245Build terrain mesh so heighmap is height of the center of the square meter.
246 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
247Terrain as mesh. (Resolution: done)
248How are static linksets seen by the physics engine?
249 Resolution: they are not linked in physics. When moved, all the children are repositioned.
250Convert BSCharacter to use all API2 (Resolution: done)
251Avatar pushing difficult (too heavy?)
252Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
253Remove old code in DLL (all non-API2 stuff). (Resolution: done)
254Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
255Debug Bullet internal stats output (why is timing all wrong?)
256 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
257Implement meshes or just verify that they work. (Resolution: they do!)
258Do prim hash codes work for sculpties and meshes? (Resolution: yes)
259Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
260 Compound shapes will need the LocalID in the shapes and collision
261 processing to get it from there.
262Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
263Package Bullet source mods for Bullet internal stats output
264 (Resolution: move code into WorldData.h rather than relying on patches)
265Single prim vehicles don't seem to properly vehiclize.
266 (Resolution: mass was not getting set properly for single prim linksets)
267Add material type linkage and input all the material property definitions.
268 Skeleton classes and table are in the sources but are not filled or used.
269 (Resolution:
270Neb vehicle taking > 25ms of physics time!!
271 (Resolution: compound linksets were being rebuild WAY too often)
272Avatar height off after unsitting (floats off ground)
273 Editting appearance then moving restores.
274 Must not be initializing height when recreating capsule after unsit.
275 (Resolution: confusion of scale vs size for native objects removed)
276Light cycle falling over when driving (Resolution: implemented angularMotorUp)
277Should vehicle angular/linear movement friction happen after all the components
278 or does it only apply to the basic movement?
279 (Resolution: friction added before returning newly computed motor value.
280 What is expected by some vehicles (turning up friction to moderate speed))
281Tune terrain/object friction to be closer to SL.
282 (Resolution: added material type with friction and resolution)
283Smooth avatar movement with motor (DONE)
284 Should motor update be all at taint-time? (Yes, DONE)
285 Fix avatar slowly sliding when standing (zero motion when stopped) (DONE)
286 (Resolution: added BSVMotor for avatar starting and stopping)
287llApplyImpulse()
288 Compare mass/movement in OS and SL. Calibrate actions. (DONE)
289 (Resolution: tested on SL and OS. AddForce scales the force for timestep)
290llSetBuoyancy() (DONE)
291 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
292Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
293 (Resolution: set default density to 3.5 (from 60) which is closer to SL)
294Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
295 (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
296Meshes rendering as bounding boxes (DONE)
297 (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
298llMoveToTarget (Resolution: added simple motor to update the position.)
299Angular motor direction is global coordinates rather than local coordinates (DONE)
300Add vehicle collisions so IsColliding is properly reported. (DONE)
301 Needed for banking, limitMotorUp, movementLimiting, ...
302 (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it)
303VehicleAddForce is not scaled by the simulation step but it is only
304 applied for one step. Should it be scaled? (DONE)
305 (Resolution: use force for timed things, Impulse for immediate, non-timed things)
306Complete implemention of preStepActions (DONE)
307 Replace vehicle step call with prestep event.
308 Is there a need for postStepActions? postStepTaints?
309Disable activity of passive linkset children. (DONE)
310 Since the linkset is a compound object, the old prims are left lying
311 around and need to be phantomized so they don't collide, ...
312Remove HeightmapInfo from terrain specification (DONE)
313 Since C++ code does not need terrain height, this structure et al are not needed.
314Surfboard go wonky when turning (DONE)
315 Angular motor direction is global coordinates rather than local coordinates?
316 (Resolution: made angular motor direction correct coordinate system)
317Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE)
318 Msg Kayaker on OSGrid when working
319 (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the
320 same in SL as in OS/BulletSim)
321Boats float low in the water (DONE)
322Boats floating at proper level (DONE)
323When is force introduced by SetForce removed? The prestep action could go forever. (DONE)
324 (Resolution: setForce registers a prestep action which keeps applying the force) \ No newline at end of file
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
index 8de70ef..ba24aa7 100644
--- a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
@@ -2190,7 +2190,7 @@ namespace OpenSim.Region.Physics.OdePlugin
2190 convex = false; 2190 convex = false;
2191 try 2191 try
2192 { 2192 {
2193 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,convex,false); 2193 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,false,convex,false);
2194 } 2194 }
2195 catch 2195 catch
2196 { 2196 {
@@ -2557,7 +2557,7 @@ namespace OpenSim.Region.Physics.OdePlugin
2557 2557
2558 try 2558 try
2559 { 2559 {
2560 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, convex,false); 2560 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, false,convex,false);
2561 } 2561 }
2562 catch 2562 catch
2563 { 2563 {
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs
index ecc2918..df980ab 100644
--- a/OpenSim/Region/Physics/Manager/IMesher.cs
+++ b/OpenSim/Region/Physics/Manager/IMesher.cs
@@ -37,7 +37,7 @@ namespace OpenSim.Region.Physics.Manager
37 { 37 {
38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); 38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); 39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
40 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde); 40 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde);
41 IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex); 41 IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex);
42 void ReleaseMesh(IMesh mesh); 42 void ReleaseMesh(IMesh mesh);
43 void ExpireReleaseMeshs(); 43 void ExpireReleaseMeshs();
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
index 9338130..e2789d6 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
@@ -349,17 +349,20 @@ namespace OpenSim.Region.Physics.Manager
349 } 349 }
350 350
351 /// <summary> 351 /// <summary>
352 /// Velocity of this actor. 352 /// The desired velocity of this actor.
353 /// </summary> 353 /// </summary>
354 /// <remarks> 354 /// <remarks>
355 /// Setting this provides a target velocity for physics scene updates. 355 /// Setting this provides a target velocity for physics scene updates.
356 /// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity, 356 /// Getting this returns the last set target. Fetch Velocity to get the current velocity.
357 /// time to accelerate and collisions.
358 /// </remarks> 357 /// </remarks>
358 protected Vector3 m_targetVelocity;
359 public virtual Vector3 TargetVelocity 359 public virtual Vector3 TargetVelocity
360 { 360 {
361 get { return Velocity; } 361 get { return m_targetVelocity; }
362 set { Velocity = value; } 362 set {
363 m_targetVelocity = value;
364 Velocity = m_targetVelocity;
365 }
363 } 366 }
364 367
365 public abstract Vector3 Velocity { get; set; } 368 public abstract Vector3 Velocity { get; set; }
diff --git a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
index 8587a2b..8ccfda5 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
@@ -30,7 +30,7 @@ using System.Collections.Generic;
30using System.IO; 30using System.IO;
31using System.Reflection; 31using System.Reflection;
32using Nini.Config; 32using Nini.Config;
33using log4net; 33using log4net;
34using OpenSim.Framework; 34using OpenSim.Framework;
35 35
36namespace OpenSim.Region.Physics.Manager 36namespace OpenSim.Region.Physics.Manager
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index 57e2d20..fe418d3 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -97,13 +97,20 @@ namespace OpenSim.Region.Physics.Manager
97// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 97// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
98 98
99 /// <summary> 99 /// <summary>
100 /// Name of this scene. Useful in debug messages to distinguish one OdeScene instance from another. 100 /// A unique identifying string for this instance of the physics engine.
101 /// Useful in debug messages to distinguish one OdeScene instance from another.
102 /// Usually set to include the region name that the physics engine is acting for.
101 /// </summary> 103 /// </summary>
102 public string Name { get; protected set; } 104 public string Name { get; protected set; }
103 105
106 /// <summary>
107 /// A string identifying the family of this physics engine. Most common values returned
108 /// are "OpenDynamicsEngine" and "BulletSim" but others are possible.
109 /// </summary>
110 public string EngineType { get; protected set; }
111
104 // The only thing that should register for this event is the SceneGraph 112 // The only thing that should register for this event is the SceneGraph
105 // Anything else could cause problems. 113 // Anything else could cause problems.
106
107 public event physicsCrash OnPhysicsCrash; 114 public event physicsCrash OnPhysicsCrash;
108 115
109 public static PhysicsScene Null 116 public static PhysicsScene Null
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
index 16846e6..80ecf66 100644
--- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs
+++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
@@ -64,16 +64,21 @@ namespace OpenSim.Region.Physics.Manager
64 { 64 {
65 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 65 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
66 { 66 {
67 return CreateMesh(primName, primShape, size, lod, false); 67 return CreateMesh(primName, primShape, size, lod, false, false);
68 } 68 }
69 69
70 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex,bool forOde) 70 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex,bool forOde)
71 { 71 {
72 return CreateMesh(primName, primShape, size, lod, false); 72 return CreateMesh(primName, primShape, size, lod, false);
73 } 73 }
74 74
75 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 75 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
76 { 76 {
77 return CreateMesh(primName, primShape, size, lod, false, false);
78 }
79
80 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
81 {
77 // Remove the reference to the encoded JPEG2000 data so it can be GCed 82 // Remove the reference to the encoded JPEG2000 data so it can be GCed
78 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; 83 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes;
79 84
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index f629c4d..d181b78 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing
321 321
322 if (primShape.SculptData.Length <= 0) 322 if (primShape.SculptData.Length <= 0)
323 { 323 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
325 // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
326 // The first time will always call with unloaded SculptData if this needs to be uploaded.
324// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); 327// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
325 return false; 328 return false;
326 } 329 }
@@ -699,16 +702,21 @@ namespace OpenSim.Region.Physics.Meshing
699 702
700 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
701 { 704 {
702 return CreateMesh(primName, primShape, size, lod, false); 705 return CreateMesh(primName, primShape, size, lod, false, true);
703 } 706 }
704 707
705 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) 708 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde)
706 { 709 {
707 return CreateMesh(primName, primShape, size, lod, false); 710 return CreateMesh(primName, primShape, size, lod, false);
708 } 711 }
709 712
710 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 713 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
711 { 714 {
715 return CreateMesh(primName, primShape, size, lod, isPhysical, true);
716 }
717
718 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
719 {
712#if SPAM 720#if SPAM
713 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); 721 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
714#endif 722#endif
@@ -718,9 +726,12 @@ namespace OpenSim.Region.Physics.Meshing
718 726
719 // If this mesh has been created already, return it instead of creating another copy 727 // If this mesh has been created already, return it instead of creating another copy
720 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory 728 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
721 key = primShape.GetMeshKey(size, lod); 729 if (shouldCache)
722 if (m_uniqueMeshes.TryGetValue(key, out mesh)) 730 {
723 return mesh; 731 key = primShape.GetMeshKey(size, lod);
732 if (m_uniqueMeshes.TryGetValue(key, out mesh))
733 return mesh;
734 }
724 735
725 if (size.X < 0.01f) size.X = 0.01f; 736 if (size.X < 0.01f) size.X = 0.01f;
726 if (size.Y < 0.01f) size.Y = 0.01f; 737 if (size.Y < 0.01f) size.Y = 0.01f;
@@ -743,7 +754,10 @@ namespace OpenSim.Region.Physics.Meshing
743 // trim the vertex and triangle lists to free up memory 754 // trim the vertex and triangle lists to free up memory
744 mesh.TrimExcess(); 755 mesh.TrimExcess();
745 756
746 m_uniqueMeshes.Add(key, mesh); 757 if (shouldCache)
758 {
759 m_uniqueMeshes.Add(key, mesh);
760 }
747 } 761 }
748 762
749 return mesh; 763 return mesh;
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index a59f63f..d09aa62 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed");
3367 _pbs.SculptData = new byte[asset.Data.Length]; 3367 _pbs.SculptData = new byte[asset.Data.Length];
3368 asset.Data.CopyTo(_pbs.SculptData, 0); 3368 asset.Data.CopyTo(_pbs.SculptData, 0);
3369// m_assetFailed = false; 3369// m_assetFailed = false;
3370
3371// m_log.DebugFormat(
3372// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
3373// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
3374
3370 m_taintshape = true; 3375 m_taintshape = true;
3371 _parent_scene.AddPhysicsActorTaint(this); 3376 _parent_scene.AddPhysicsActorTaint(this);
3372 } 3377 }
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
index 478dd95..07663b3 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
@@ -72,7 +72,7 @@ namespace OpenSim.Region.Physics.OdePlugin
72 // http://opensimulator.org/mantis/view.php?id=2750). 72 // http://opensimulator.org/mantis/view.php?id=2750).
73 d.InitODE(); 73 d.InitODE();
74 74
75 m_scene = new OdeScene(sceneIdentifier); 75 m_scene = new OdeScene(GetName(), sceneIdentifier);
76 } 76 }
77 77
78 return m_scene; 78 return m_scene;
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index d53bd90..02a0b15 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -526,11 +526,12 @@ namespace OpenSim.Region.Physics.OdePlugin
526 /// These settings need to be tweaked 'exactly' right or weird stuff happens. 526 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
527 /// </summary> 527 /// </summary>
528 /// <param value="name">Name of the scene. Useful in debug messages.</param> 528 /// <param value="name">Name of the scene. Useful in debug messages.</param>
529 public OdeScene(string name) 529 public OdeScene(string engineType, string name)
530 { 530 {
531 m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name); 531 m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name);
532 532
533 Name = name; 533 Name = name;
534 EngineType = engineType;
534 535
535 nearCallback = near; 536 nearCallback = near;
536 triCallback = TriCallback; 537 triCallback = TriCallback;
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
index cbc6b95..16404c6 100644
--- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
+++ b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
@@ -32,13 +32,14 @@ using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.OdePlugin; 34using OpenSim.Region.Physics.OdePlugin;
35using OpenSim.Tests.Common;
35using log4net; 36using log4net;
36using System.Reflection; 37using System.Reflection;
37 38
38namespace OpenSim.Region.Physics.OdePlugin.Tests 39namespace OpenSim.Region.Physics.OdePlugin.Tests
39{ 40{
40 [TestFixture] 41 [TestFixture]
41 public class ODETestClass 42 public class ODETestClass : OpenSimTestCase
42 { 43 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 45
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs
index e6b42e6..ed086dd 100644
--- a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs
+++ b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Region.Physics.POSPlugin
49 49
50 public PhysicsScene GetScene(string sceneIdentifier) 50 public PhysicsScene GetScene(string sceneIdentifier)
51 { 51 {
52 return new POSScene(sceneIdentifier); 52 return new POSScene(GetName(), sceneIdentifier);
53 } 53 }
54 54
55 public string GetName() 55 public string GetName()
diff --git a/OpenSim/Region/Physics/POSPlugin/POSScene.cs b/OpenSim/Region/Physics/POSPlugin/POSScene.cs
index 2f24a50..d30d482 100644
--- a/OpenSim/Region/Physics/POSPlugin/POSScene.cs
+++ b/OpenSim/Region/Physics/POSPlugin/POSScene.cs
@@ -43,8 +43,10 @@ namespace OpenSim.Region.Physics.POSPlugin
43 43
44 //protected internal string sceneIdentifier; 44 //protected internal string sceneIdentifier;
45 45
46 public POSScene(String _sceneIdentifier) 46 public POSScene(string engineType, String _sceneIdentifier)
47 { 47 {
48 EngineType = engineType;
49 Name = EngineType + "/" + _sceneIdentifier;
48 //sceneIdentifier = _sceneIdentifier; 50 //sceneIdentifier = _sceneIdentifier;
49 } 51 }
50 52
diff --git a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
index 6e1a105..00cbfbd 100644
--- a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
@@ -1031,12 +1031,12 @@ namespace OpenSim.Region.Physics.Meshing
1031 1031
1032 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 1032 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
1033 { 1033 {
1034 return CreateMesh(primName, primShape, size, lod, false,false,false); 1034 return CreateMesh(primName, primShape, size, lod, false,false,false,false);
1035 } 1035 }
1036 1036
1037 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 1037 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
1038 { 1038 {
1039 return CreateMesh(primName, primShape, size, lod, false,false,false); 1039 return CreateMesh(primName, primShape, size, lod, false,false,false,false);
1040 } 1040 }
1041 1041
1042 public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) 1042 public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
@@ -1080,7 +1080,7 @@ namespace OpenSim.Region.Physics.Meshing
1080 1080
1081 private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); 1081 private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f);
1082 1082
1083 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) 1083 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde)
1084 { 1084 {
1085#if SPAM 1085#if SPAM
1086 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); 1086 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
index 5030cec..0df71eb 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
@@ -448,7 +448,7 @@ namespace OpenSim.Region.Physics.OdePlugin
448 else 448 else
449 { 449 {
450 repData.meshState = MeshState.needMesh; 450 repData.meshState = MeshState.needMesh;
451 mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); 451 mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true);
452 if (mesh == null) 452 if (mesh == null)
453 { 453 {
454 repData.meshState = MeshState.MeshFailed; 454 repData.meshState = MeshState.MeshFailed;
@@ -513,7 +513,7 @@ namespace OpenSim.Region.Physics.OdePlugin
513 clod = (int)LevelOfDetail.Low; 513 clod = (int)LevelOfDetail.Low;
514 } 514 }
515 515
516 mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); 516 mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true);
517 517
518 if (mesh == null) 518 if (mesh == null)
519 { 519 {
@@ -929,4 +929,4 @@ namespace OpenSim.Region.Physics.OdePlugin
929 repData.actor.Name); 929 repData.actor.Name);
930 } 930 }
931 } 931 }
932} \ No newline at end of file 932}