aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS')
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs2120
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs2589
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs457
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs174
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs219
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs220
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs138
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs139
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActors.cs154
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs763
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs813
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs144
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs180
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs181
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs54
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs55
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs55
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs103
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs1800
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs503
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs477
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs854
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs203
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSMotors.cs451
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSParam.cs927
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs620
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs76
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs1896
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs182
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs350
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSScene.cs1281
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs425
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapes.cs1463
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs170
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs585
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs441
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs277
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt379
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs33
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs156
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs56
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs100
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs205
43 files changed, 22468 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
new file mode 100755
index 0000000..3bd81d4
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
@@ -0,0 +1,2120 @@
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 shapeType = 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, shapeType);
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 CreateGImpactShape(BulletWorld world,
255 int indicesCount, int[] indices,
256 int verticesCount, float[] vertices)
257{
258 BulletWorldUnman worldu = world as BulletWorldUnman;
259 return new BulletShapeUnman(
260 BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
261 BSPhysicsShapeType.SHAPE_GIMPACT);
262}
263
264public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
265{
266 BulletWorldUnman worldu = world as BulletWorldUnman;
267 return new BulletShapeUnman(
268 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
269 BSPhysicsShapeType.SHAPE_HULL);
270}
271
272public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
273{
274 BulletWorldUnman worldu = world as BulletWorldUnman;
275 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
276 return new BulletShapeUnman(
277 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms),
278 BSPhysicsShapeType.SHAPE_HULL);
279}
280
281public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
282{
283 BulletWorldUnman worldu = world as BulletWorldUnman;
284 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
285 return new BulletShapeUnman(
286 BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
287 BSPhysicsShapeType.SHAPE_CONVEXHULL);
288}
289
290public override BulletShape CreateConvexHullShape(BulletWorld world,
291 int indicesCount, int[] indices,
292 int verticesCount, float[] vertices)
293{
294 BulletWorldUnman worldu = world as BulletWorldUnman;
295 return new BulletShapeUnman(
296 BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
297 BSPhysicsShapeType.SHAPE_CONVEXHULL);
298}
299
300public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
301{
302 BulletWorldUnman worldu = world as BulletWorldUnman;
303 return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type);
304}
305
306public override bool IsNativeShape(BulletShape shape)
307{
308 BulletShapeUnman shapeu = shape as BulletShapeUnman;
309 if (shapeu != null && shapeu.HasPhysicalShape)
310 return BSAPICPP.IsNativeShape2(shapeu.ptr);
311 return false;
312}
313
314public override void SetShapeCollisionMargin(BulletShape shape, float margin)
315{
316 BulletShapeUnman shapeu = shape as BulletShapeUnman;
317 if (shapeu != null && shapeu.HasPhysicalShape)
318 BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
319}
320
321public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
322{
323 BulletWorldUnman worldu = world as BulletWorldUnman;
324 return new BulletShapeUnman(
325 BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale),
326 BSPhysicsShapeType.SHAPE_CAPSULE);
327}
328
329public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree)
330{
331 BulletWorldUnman worldu = world as BulletWorldUnman;
332 return new BulletShapeUnman(
333 BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree),
334 BSPhysicsShapeType.SHAPE_COMPOUND);
335
336}
337
338public override int GetNumberOfCompoundChildren(BulletShape shape)
339{
340 BulletShapeUnman shapeu = shape as BulletShapeUnman;
341 if (shapeu != null && shapeu.HasPhysicalShape)
342 return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr);
343 return 0;
344}
345
346public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot)
347{
348 BulletShapeUnman shapeu = shape as BulletShapeUnman;
349 BulletShapeUnman addShapeu = addShape as BulletShapeUnman;
350 BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot);
351}
352
353public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
354{
355 BulletShapeUnman shapeu = shape as BulletShapeUnman;
356 return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
357}
358
359public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
360{
361 BulletShapeUnman shapeu = shape as BulletShapeUnman;
362 return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
363}
364
365public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape)
366{
367 BulletShapeUnman shapeu = shape as BulletShapeUnman;
368 BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman;
369 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
370}
371
372public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb)
373{
374 BulletShapeUnman shapeu = pShape as BulletShapeUnman;
375 BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb);
376}
377
378public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
379{
380 BulletShapeUnman shapeu = shape as BulletShapeUnman;
381 BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr);
382}
383
384public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id)
385{
386 BulletWorldUnman worldu = world as BulletWorldUnman;
387 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
388 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
389}
390
391public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
392{
393 BulletWorldUnman worldu = world as BulletWorldUnman;
394 BulletShapeUnman shapeu = shape as BulletShapeUnman;
395 return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr);
396}
397
398public override CollisionObjectTypes GetBodyType(BulletBody obj)
399{
400 BulletBodyUnman bodyu = obj as BulletBodyUnman;
401 return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr);
402}
403
404public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
405{
406 BulletWorldUnman worldu = world as BulletWorldUnman;
407 BulletShapeUnman shapeu = shape as BulletShapeUnman;
408 return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
409}
410
411public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot)
412{
413 BulletShapeUnman shapeu = shape as BulletShapeUnman;
414 return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot));
415}
416
417public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
418{
419 BulletWorldUnman worldu = world as BulletWorldUnman;
420 BulletShapeUnman shapeu = shape as BulletShapeUnman;
421 return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
422}
423
424public override void DestroyObject(BulletWorld world, BulletBody obj)
425{
426 BulletWorldUnman worldu = world as BulletWorldUnman;
427 BulletBodyUnman bodyu = obj as BulletBodyUnman;
428 BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr);
429}
430
431// =====================================================================================
432// Terrain creation and helper routines
433public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin)
434{
435 return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE);
436}
437
438public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
439 float scaleFactor, float collisionMargin)
440{
441 return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin),
442 BSPhysicsShapeType.SHAPE_TERRAIN);
443}
444
445// =====================================================================================
446// Constraint creation and helper routines
447public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
448 Vector3 frame1loc, Quaternion frame1rot,
449 Vector3 frame2loc, Quaternion frame2rot,
450 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
451{
452 BulletWorldUnman worldu = world as BulletWorldUnman;
453 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
454 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
455 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
456 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
457}
458
459public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
460 Vector3 joinPoint,
461 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
462{
463 BulletWorldUnman worldu = world as BulletWorldUnman;
464 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
465 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
466 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
467 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
468}
469
470public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
471 Vector3 frameInBloc, Quaternion frameInBrot,
472 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
473{
474 BulletWorldUnman worldu = world as BulletWorldUnman;
475 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
476 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr,
477 frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies));
478}
479
480public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
481 Vector3 frame1loc, Quaternion frame1rot,
482 Vector3 frame2loc, Quaternion frame2rot,
483 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
484{
485 BulletWorldUnman worldu = world as BulletWorldUnman;
486 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
487 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
488 return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
489 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
490}
491
492public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
493 Vector3 pivotinA, Vector3 pivotinB,
494 Vector3 axisInA, Vector3 axisInB,
495 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
496{
497 BulletWorldUnman worldu = world as BulletWorldUnman;
498 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
499 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
500 return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
501 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
502}
503
504public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
505 Vector3 frame1loc, Quaternion frame1rot,
506 Vector3 frame2loc, Quaternion frame2rot,
507 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
508{
509 BulletWorldUnman worldu = world as BulletWorldUnman;
510 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
511 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
512 return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
513 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
514}
515
516public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
517 Vector3 frame1loc, Quaternion frame1rot,
518 Vector3 frame2loc, Quaternion frame2rot,
519 bool disableCollisionsBetweenLinkedBodies)
520{
521 BulletWorldUnman worldu = world as BulletWorldUnman;
522 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
523 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
524 return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
525 frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies));
526}
527
528public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
529 Vector3 axisInA, Vector3 axisInB,
530 float ratio, bool disableCollisionsBetweenLinkedBodies)
531{
532 BulletWorldUnman worldu = world as BulletWorldUnman;
533 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
534 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
535 return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB,
536 ratio, disableCollisionsBetweenLinkedBodies));
537}
538
539public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
540 Vector3 pivotInA, Vector3 pivotInB,
541 bool disableCollisionsBetweenLinkedBodies)
542{
543 BulletWorldUnman worldu = world as BulletWorldUnman;
544 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
545 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
546 return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB,
547 disableCollisionsBetweenLinkedBodies));
548}
549
550public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
551{
552 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
553 BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
554}
555
556public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
557{
558 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
559 BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
560}
561
562public override bool SetFrames(BulletConstraint constrain,
563 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
564{
565 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
566 return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
567}
568
569public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
570{
571 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
572 return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
573}
574
575public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
576{
577 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
578 return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
579}
580
581public override bool UseFrameOffset(BulletConstraint constrain, float enable)
582{
583 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
584 return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
585}
586
587public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
588{
589 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
590 return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
591}
592
593public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
594{
595 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
596 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
597}
598
599public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation)
600{
601 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
602 return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation);
603}
604
605public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse)
606{
607 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
608 return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse);
609}
610
611public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint)
612{
613 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
614 return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint);
615}
616
617public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss)
618{
619 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
620 return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss);
621}
622
623public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping)
624{
625 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
626 return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping);
627}
628
629public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val)
630{
631 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
632 return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val);
633}
634
635public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val)
636{
637 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
638 return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val);
639}
640
641public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse)
642{
643 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
644 return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse);
645}
646
647public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val)
648{
649 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
650 return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val);
651}
652
653public override bool CalculateTransforms(BulletConstraint constrain)
654{
655 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
656 return BSAPICPP.CalculateTransforms2(constrainu.ptr);
657}
658
659public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
660{
661 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
662 return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
663}
664
665public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
666{
667 BulletWorldUnman worldu = world as BulletWorldUnman;
668 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
669 return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
670}
671
672// =====================================================================================
673// btCollisionWorld entries
674public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
675{
676 BulletWorldUnman worldu = world as BulletWorldUnman;
677 BulletBodyUnman bodyu = obj as BulletBodyUnman;
678 BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
679}
680
681public override void UpdateAabbs(BulletWorld world)
682{
683 BulletWorldUnman worldu = world as BulletWorldUnman;
684 BSAPICPP.UpdateAabbs2(worldu.ptr);
685}
686
687public override bool GetForceUpdateAllAabbs(BulletWorld world)
688{
689 BulletWorldUnman worldu = world as BulletWorldUnman;
690 return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
691}
692
693public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
694{
695 BulletWorldUnman worldu = world as BulletWorldUnman;
696 BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
697}
698
699// =====================================================================================
700// btDynamicsWorld entries
701public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
702{
703 BulletWorldUnman worldu = world as BulletWorldUnman;
704 BulletBodyUnman bodyu = obj as BulletBodyUnman;
705
706 // Bullet resets several variables when an object is added to the world.
707 // Gravity is reset to world default depending on the static/dynamic
708 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
709 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
710
711 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
712
713 if (ret)
714 {
715 BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
716 obj.ApplyCollisionMask(world.physicsScene);
717 }
718 return ret;
719}
720
721public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
722{
723 BulletWorldUnman worldu = world as BulletWorldUnman;
724 BulletBodyUnman bodyu = obj as BulletBodyUnman;
725 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
726}
727
728public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj)
729{
730 BulletWorldUnman worldu = world as BulletWorldUnman;
731 BulletBodyUnman bodyu = obj as BulletBodyUnman;
732 return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr);
733}
734
735public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
736{
737 BulletWorldUnman worldu = world as BulletWorldUnman;
738 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
739 return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
740}
741
742public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
743{
744 BulletWorldUnman worldu = world as BulletWorldUnman;
745 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
746 return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
747}
748// =====================================================================================
749// btCollisionObject entries
750public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
751{
752 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
753 return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
754}
755
756public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
757{
758 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
759 return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
760}
761
762public override bool HasAnisotripicFriction(BulletConstraint constrain)
763{
764 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
765 return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
766}
767
768public override void SetContactProcessingThreshold(BulletBody obj, float val)
769{
770 BulletBodyUnman bodyu = obj as BulletBodyUnman;
771 BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
772}
773
774public override float GetContactProcessingThreshold(BulletBody obj)
775{
776 BulletBodyUnman bodyu = obj as BulletBodyUnman;
777 return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
778}
779
780public override bool IsStaticObject(BulletBody obj)
781{
782 BulletBodyUnman bodyu = obj as BulletBodyUnman;
783 return BSAPICPP.IsStaticObject2(bodyu.ptr);
784}
785
786public override bool IsKinematicObject(BulletBody obj)
787{
788 BulletBodyUnman bodyu = obj as BulletBodyUnman;
789 return BSAPICPP.IsKinematicObject2(bodyu.ptr);
790}
791
792public override bool IsStaticOrKinematicObject(BulletBody obj)
793{
794 BulletBodyUnman bodyu = obj as BulletBodyUnman;
795 return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
796}
797
798public override bool HasContactResponse(BulletBody obj)
799{
800 BulletBodyUnman bodyu = obj as BulletBodyUnman;
801 return BSAPICPP.HasContactResponse2(bodyu.ptr);
802}
803
804public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
805{
806 BulletWorldUnman worldu = world as BulletWorldUnman;
807 BulletBodyUnman bodyu = obj as BulletBodyUnman;
808 BulletShapeUnman shapeu = shape as BulletShapeUnman;
809 if (worldu != null && bodyu != null)
810 {
811 // Special case to allow the caller to zero out the reference to any physical shape
812 if (shapeu != null)
813 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
814 else
815 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
816 }
817}
818
819public override BulletShape GetCollisionShape(BulletBody obj)
820{
821 BulletBodyUnman bodyu = obj as BulletBodyUnman;
822 return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
823}
824
825public override int GetActivationState(BulletBody obj)
826{
827 BulletBodyUnman bodyu = obj as BulletBodyUnman;
828 return BSAPICPP.GetActivationState2(bodyu.ptr);
829}
830
831public override void SetActivationState(BulletBody obj, int state)
832{
833 BulletBodyUnman bodyu = obj as BulletBodyUnman;
834 BSAPICPP.SetActivationState2(bodyu.ptr, state);
835}
836
837public override void SetDeactivationTime(BulletBody obj, float dtime)
838{
839 BulletBodyUnman bodyu = obj as BulletBodyUnman;
840 BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
841}
842
843public override float GetDeactivationTime(BulletBody obj)
844{
845 BulletBodyUnman bodyu = obj as BulletBodyUnman;
846 return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
847}
848
849public override void ForceActivationState(BulletBody obj, ActivationState state)
850{
851 BulletBodyUnman bodyu = obj as BulletBodyUnman;
852 BSAPICPP.ForceActivationState2(bodyu.ptr, state);
853}
854
855public override void Activate(BulletBody obj, bool forceActivation)
856{
857 BulletBodyUnman bodyu = obj as BulletBodyUnman;
858 BSAPICPP.Activate2(bodyu.ptr, forceActivation);
859}
860
861public override bool IsActive(BulletBody obj)
862{
863 BulletBodyUnman bodyu = obj as BulletBodyUnman;
864 return BSAPICPP.IsActive2(bodyu.ptr);
865}
866
867public override void SetRestitution(BulletBody obj, float val)
868{
869 BulletBodyUnman bodyu = obj as BulletBodyUnman;
870 BSAPICPP.SetRestitution2(bodyu.ptr, val);
871}
872
873public override float GetRestitution(BulletBody obj)
874{
875 BulletBodyUnman bodyu = obj as BulletBodyUnman;
876 return BSAPICPP.GetRestitution2(bodyu.ptr);
877}
878
879public override void SetFriction(BulletBody obj, float val)
880{
881 BulletBodyUnman bodyu = obj as BulletBodyUnman;
882 BSAPICPP.SetFriction2(bodyu.ptr, val);
883}
884
885public override float GetFriction(BulletBody obj)
886{
887 BulletBodyUnman bodyu = obj as BulletBodyUnman;
888 return BSAPICPP.GetFriction2(bodyu.ptr);
889}
890
891public override Vector3 GetPosition(BulletBody obj)
892{
893 BulletBodyUnman bodyu = obj as BulletBodyUnman;
894 return BSAPICPP.GetPosition2(bodyu.ptr);
895}
896
897public override Quaternion GetOrientation(BulletBody obj)
898{
899 BulletBodyUnman bodyu = obj as BulletBodyUnman;
900 return BSAPICPP.GetOrientation2(bodyu.ptr);
901}
902
903public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
904{
905 BulletBodyUnman bodyu = obj as BulletBodyUnman;
906 BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
907}
908
909 /*
910public override IntPtr GetBroadphaseHandle(BulletBody obj)
911{
912 BulletBodyUnman bodyu = obj as BulletBodyUnman;
913 return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
914}
915
916public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
917{
918 BulletBodyUnman bodyu = obj as BulletBodyUnman;
919 BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
920}
921 */
922
923public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
924{
925 BulletBodyUnman bodyu = obj as BulletBodyUnman;
926 BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
927}
928
929public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
930{
931 BulletBodyUnman bodyu = obj as BulletBodyUnman;
932 BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
933}
934
935public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
936{
937 BulletBodyUnman bodyu = obj as BulletBodyUnman;
938 BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
939}
940
941public override float GetHitFraction(BulletBody obj)
942{
943 BulletBodyUnman bodyu = obj as BulletBodyUnman;
944 return BSAPICPP.GetHitFraction2(bodyu.ptr);
945}
946
947public override void SetHitFraction(BulletBody obj, float val)
948{
949 BulletBodyUnman bodyu = obj as BulletBodyUnman;
950 BSAPICPP.SetHitFraction2(bodyu.ptr, val);
951}
952
953public override CollisionFlags GetCollisionFlags(BulletBody obj)
954{
955 BulletBodyUnman bodyu = obj as BulletBodyUnman;
956 return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
957}
958
959public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
960{
961 BulletBodyUnman bodyu = obj as BulletBodyUnman;
962 return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
963}
964
965public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
966{
967 BulletBodyUnman bodyu = obj as BulletBodyUnman;
968 return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
969}
970
971public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
972{
973 BulletBodyUnman bodyu = obj as BulletBodyUnman;
974 return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
975}
976
977public override float GetCcdMotionThreshold(BulletBody obj)
978{
979 BulletBodyUnman bodyu = obj as BulletBodyUnman;
980 return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
981}
982
983
984public override void SetCcdMotionThreshold(BulletBody obj, float val)
985{
986 BulletBodyUnman bodyu = obj as BulletBodyUnman;
987 BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
988}
989
990public override float GetCcdSweptSphereRadius(BulletBody obj)
991{
992 BulletBodyUnman bodyu = obj as BulletBodyUnman;
993 return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
994}
995
996public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
997{
998 BulletBodyUnman bodyu = obj as BulletBodyUnman;
999 BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
1000}
1001
1002public override IntPtr GetUserPointer(BulletBody obj)
1003{
1004 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1005 return BSAPICPP.GetUserPointer2(bodyu.ptr);
1006}
1007
1008public override void SetUserPointer(BulletBody obj, IntPtr val)
1009{
1010 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1011 BSAPICPP.SetUserPointer2(bodyu.ptr, val);
1012}
1013
1014// =====================================================================================
1015// btRigidBody entries
1016public override void ApplyGravity(BulletBody obj)
1017{
1018 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1019 BSAPICPP.ApplyGravity2(bodyu.ptr);
1020}
1021
1022public override void SetGravity(BulletBody obj, Vector3 val)
1023{
1024 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1025 BSAPICPP.SetGravity2(bodyu.ptr, val);
1026}
1027
1028public override Vector3 GetGravity(BulletBody obj)
1029{
1030 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1031 return BSAPICPP.GetGravity2(bodyu.ptr);
1032}
1033
1034public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
1035{
1036 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1037 BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
1038}
1039
1040public override void SetLinearDamping(BulletBody obj, float lin_damping)
1041{
1042 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1043 BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
1044}
1045
1046public override void SetAngularDamping(BulletBody obj, float ang_damping)
1047{
1048 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1049 BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
1050}
1051
1052public override float GetLinearDamping(BulletBody obj)
1053{
1054 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1055 return BSAPICPP.GetLinearDamping2(bodyu.ptr);
1056}
1057
1058public override float GetAngularDamping(BulletBody obj)
1059{
1060 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1061 return BSAPICPP.GetAngularDamping2(bodyu.ptr);
1062}
1063
1064public override float GetLinearSleepingThreshold(BulletBody obj)
1065{
1066 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1067 return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
1068}
1069
1070public override void ApplyDamping(BulletBody obj, float timeStep)
1071{
1072 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1073 BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
1074}
1075
1076public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
1077{
1078 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1079 BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
1080}
1081
1082public override Vector3 GetLinearFactor(BulletBody obj)
1083{
1084 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1085 return BSAPICPP.GetLinearFactor2(bodyu.ptr);
1086}
1087
1088public override void SetLinearFactor(BulletBody obj, Vector3 factor)
1089{
1090 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1091 BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
1092}
1093
1094public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
1095{
1096 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1097 BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
1098}
1099
1100// Add a force to the object as if its mass is one.
1101// Deep down in Bullet: m_totalForce += force*m_linearFactor;
1102public override void ApplyCentralForce(BulletBody obj, Vector3 force)
1103{
1104 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1105 BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
1106}
1107
1108// Set the force being applied to the object as if its mass is one.
1109public override void SetObjectForce(BulletBody obj, Vector3 force)
1110{
1111 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1112 BSAPICPP.SetObjectForce2(bodyu.ptr, force);
1113}
1114
1115public override Vector3 GetTotalForce(BulletBody obj)
1116{
1117 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1118 return BSAPICPP.GetTotalForce2(bodyu.ptr);
1119}
1120
1121public override Vector3 GetTotalTorque(BulletBody obj)
1122{
1123 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1124 return BSAPICPP.GetTotalTorque2(bodyu.ptr);
1125}
1126
1127public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
1128{
1129 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1130 return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
1131}
1132
1133public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
1134{
1135 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1136 BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
1137}
1138
1139public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
1140{
1141 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1142 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
1143}
1144
1145// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
1146public override void ApplyTorque(BulletBody obj, Vector3 torque)
1147{
1148 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1149 BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
1150}
1151
1152// Apply force at the given point. Will add torque to the object.
1153// Deep down in Bullet: applyCentralForce(force);
1154// applyTorque(rel_pos.cross(force*m_linearFactor));
1155public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
1156{
1157 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1158 BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
1159}
1160
1161// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1162// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
1163public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
1164{
1165 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1166 BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
1167}
1168
1169// Apply impulse to the object's torque. Force is scaled by object's mass.
1170// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
1171public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
1172{
1173 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1174 BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
1175}
1176
1177// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1178// Deep down in Bullet: applyCentralImpulse(impulse);
1179// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
1180public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
1181{
1182 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1183 BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
1184}
1185
1186public override void ClearForces(BulletBody obj)
1187{
1188 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1189 BSAPICPP.ClearForces2(bodyu.ptr);
1190}
1191
1192public override void ClearAllForces(BulletBody obj)
1193{
1194 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1195 BSAPICPP.ClearAllForces2(bodyu.ptr);
1196}
1197
1198public override void UpdateInertiaTensor(BulletBody obj)
1199{
1200 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1201 BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
1202}
1203
1204public override Vector3 GetLinearVelocity(BulletBody obj)
1205{
1206 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1207 return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
1208}
1209
1210public override Vector3 GetAngularVelocity(BulletBody obj)
1211{
1212 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1213 return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
1214}
1215
1216public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
1217{
1218 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1219 BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
1220}
1221
1222public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
1223{
1224 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1225 BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
1226}
1227
1228public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
1229{
1230 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1231 return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
1232}
1233
1234public override void Translate(BulletBody obj, Vector3 trans)
1235{
1236 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1237 BSAPICPP.Translate2(bodyu.ptr, trans);
1238}
1239
1240public override void UpdateDeactivation(BulletBody obj, float timeStep)
1241{
1242 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1243 BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
1244}
1245
1246public override bool WantsSleeping(BulletBody obj)
1247{
1248 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1249 return BSAPICPP.WantsSleeping2(bodyu.ptr);
1250}
1251
1252public override void SetAngularFactor(BulletBody obj, float factor)
1253{
1254 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1255 BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
1256}
1257
1258public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
1259{
1260 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1261 BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
1262}
1263
1264public override Vector3 GetAngularFactor(BulletBody obj)
1265{
1266 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1267 return BSAPICPP.GetAngularFactor2(bodyu.ptr);
1268}
1269
1270public override bool IsInWorld(BulletWorld world, BulletBody obj)
1271{
1272 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1273 return BSAPICPP.IsInWorld2(bodyu.ptr);
1274}
1275
1276public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
1277{
1278 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1279 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1280 BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
1281}
1282
1283public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
1284{
1285 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1286 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1287 BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
1288}
1289
1290public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
1291{
1292 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1293 return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
1294}
1295
1296public override int GetNumConstraintRefs(BulletBody obj)
1297{
1298 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1299 return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
1300}
1301
1302public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
1303{
1304 BulletBodyUnman bodyu = body as BulletBodyUnman;
1305 return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
1306}
1307
1308// =====================================================================================
1309// btCollisionShape entries
1310
1311public override float GetAngularMotionDisc(BulletShape shape)
1312{
1313 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1314 return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
1315}
1316
1317public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
1318{
1319 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1320 return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
1321}
1322
1323public override bool IsPolyhedral(BulletShape shape)
1324{
1325 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1326 return BSAPICPP.IsPolyhedral2(shapeu.ptr);
1327}
1328
1329public override bool IsConvex2d(BulletShape shape)
1330{
1331 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1332 return BSAPICPP.IsConvex2d2(shapeu.ptr);
1333}
1334
1335public override bool IsConvex(BulletShape shape)
1336{
1337 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1338 return BSAPICPP.IsConvex2(shapeu.ptr);
1339}
1340
1341public override bool IsNonMoving(BulletShape shape)
1342{
1343 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1344 return BSAPICPP.IsNonMoving2(shapeu.ptr);
1345}
1346
1347public override bool IsConcave(BulletShape shape)
1348{
1349 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1350 return BSAPICPP.IsConcave2(shapeu.ptr);
1351}
1352
1353public override bool IsCompound(BulletShape shape)
1354{
1355 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1356 return BSAPICPP.IsCompound2(shapeu.ptr);
1357}
1358
1359public override bool IsSoftBody(BulletShape shape)
1360{
1361 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1362 return BSAPICPP.IsSoftBody2(shapeu.ptr);
1363}
1364
1365public override bool IsInfinite(BulletShape shape)
1366{
1367 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1368 return BSAPICPP.IsInfinite2(shapeu.ptr);
1369}
1370
1371public override void SetLocalScaling(BulletShape shape, Vector3 scale)
1372{
1373 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1374 BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
1375}
1376
1377public override Vector3 GetLocalScaling(BulletShape shape)
1378{
1379 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1380 return BSAPICPP.GetLocalScaling2(shapeu.ptr);
1381}
1382
1383public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
1384{
1385 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1386 return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
1387}
1388
1389public override int GetShapeType(BulletShape shape)
1390{
1391 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1392 return BSAPICPP.GetShapeType2(shapeu.ptr);
1393}
1394
1395public override void SetMargin(BulletShape shape, float val)
1396{
1397 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1398 BSAPICPP.SetMargin2(shapeu.ptr, val);
1399}
1400
1401public override float GetMargin(BulletShape shape)
1402{
1403 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1404 return BSAPICPP.GetMargin2(shapeu.ptr);
1405}
1406
1407// =====================================================================================
1408// Debugging
1409public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1410{
1411 BulletWorldUnman worldu = world as BulletWorldUnman;
1412 BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
1413 BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
1414}
1415
1416public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
1417{
1418 BulletWorldUnman worldu = world as BulletWorldUnman;
1419 BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
1420 BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
1421}
1422
1423public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
1424{
1425 BulletWorldUnman worldu = world as BulletWorldUnman;
1426 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1427 BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
1428}
1429
1430public override void DumpActivationInfo(BulletWorld world)
1431{
1432 BulletWorldUnman worldu = world as BulletWorldUnman;
1433 BSAPICPP.DumpActivationInfo2(worldu.ptr);
1434}
1435
1436public override void DumpAllInfo(BulletWorld world)
1437{
1438 BulletWorldUnman worldu = world as BulletWorldUnman;
1439 BSAPICPP.DumpAllInfo2(worldu.ptr);
1440}
1441
1442public override void DumpPhysicsStatistics(BulletWorld world)
1443{
1444 BulletWorldUnman worldu = world as BulletWorldUnman;
1445 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1446}
1447public override void ResetBroadphasePool(BulletWorld world)
1448{
1449 BulletWorldUnman worldu = world as BulletWorldUnman;
1450 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1451}
1452public override void ResetConstraintSolver(BulletWorld world)
1453{
1454 BulletWorldUnman worldu = world as BulletWorldUnman;
1455 BSAPICPP.ResetConstraintSolver(worldu.ptr);
1456}
1457
1458// =====================================================================================
1459// =====================================================================================
1460// =====================================================================================
1461// =====================================================================================
1462// =====================================================================================
1463// The actual interface to the unmanaged code
1464static class BSAPICPP
1465{
1466// ===============================================================================
1467// Link back to the managed code for outputting log messages
1468[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1469public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
1470
1471// ===============================================================================
1472// Initialization and simulation
1473[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1474public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
1475 int maxCollisions, IntPtr collisionArray,
1476 int maxUpdates, IntPtr updateArray,
1477 DebugLogCallback logRoutine);
1478
1479[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1480public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
1481 out int updatedEntityCount, out int collidersCount);
1482
1483[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1484public static extern void Shutdown2(IntPtr sim);
1485
1486[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1487public static extern bool PushUpdate2(IntPtr obj);
1488
1489[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1490public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
1491
1492// =====================================================================================
1493// Mesh, hull, shape and body creation helper routines
1494[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1495public static extern IntPtr CreateMeshShape2(IntPtr world,
1496 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1497 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1498
1499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1500public static extern IntPtr CreateGImpactShape2(IntPtr world,
1501 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1502 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1503
1504[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1505public static extern IntPtr CreateHullShape2(IntPtr world,
1506 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1507
1508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1509public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms);
1510
1511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1512public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1513
1514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1515public static extern IntPtr CreateConvexHullShape2(IntPtr world,
1516 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1517 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1518
1519[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1520public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1521
1522[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1523public static extern bool IsNativeShape2(IntPtr shape);
1524
1525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1526public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
1527
1528[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1529public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
1530
1531[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1532public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
1533
1534[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1535public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
1536
1537[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1538public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
1539
1540[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1541public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1542
1543[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1544public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1545
1546[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1547public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1548
1549[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1550public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
1551
1552[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1553public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1554
1555[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1556public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
1557
1558[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1559public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
1560
1561[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1562public static extern int GetBodyType2(IntPtr obj);
1563
1564[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1565public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1566
1567[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1568public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1569
1570[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1571public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1572
1573[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1574public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1575
1576// =====================================================================================
1577// Terrain creation and helper routines
1578[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1579public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1580
1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1582public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1583 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1584 float scaleFactor, float collisionMargin);
1585
1586// =====================================================================================
1587// Constraint creation and helper routines
1588[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1589public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1590 Vector3 frame1loc, Quaternion frame1rot,
1591 Vector3 frame2loc, Quaternion frame2rot,
1592 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1593
1594[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1595public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1596 Vector3 joinPoint,
1597 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1598
1599[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1600public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1,
1601 Vector3 frameInBloc, Quaternion frameInBrot,
1602 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
1603
1604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1605public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1606 Vector3 frame1loc, Quaternion frame1rot,
1607 Vector3 frame2loc, Quaternion frame2rot,
1608 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1609
1610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1611public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1612 Vector3 pivotinA, Vector3 pivotinB,
1613 Vector3 axisInA, Vector3 axisInB,
1614 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1615
1616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1617public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1618 Vector3 frameInAloc, Quaternion frameInArot,
1619 Vector3 frameInBloc, Quaternion frameInBrot,
1620 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1621
1622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1623public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1624 Vector3 frameInAloc, Quaternion frameInArot,
1625 Vector3 frameInBloc, Quaternion frameInBrot,
1626 bool disableCollisionsBetweenLinkedBodies);
1627
1628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1629public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1630 Vector3 axisInA, Vector3 axisInB,
1631 float ratio, bool disableCollisionsBetweenLinkedBodies);
1632
1633[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1634public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1635 Vector3 pivotInA, Vector3 pivotInB,
1636 bool disableCollisionsBetweenLinkedBodies);
1637
1638
1639[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1640public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1641
1642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1643public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
1644
1645[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1646public static extern bool SetFrames2(IntPtr constrain,
1647 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
1648
1649[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1650public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1651
1652[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1653public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1654
1655[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1656public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
1657
1658[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1659public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
1660
1661[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1662public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1663
1664[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1665public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation);
1666
1667[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1668public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse);
1669
1670[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1671public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint);
1672
1673[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1674public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness);
1675
1676[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1677public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping);
1678
1679[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1680public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val);
1681
1682[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1683public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
1684
1685[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1686public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse);
1687
1688[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1689public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val);
1690
1691[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1692public static extern bool CalculateTransforms2(IntPtr constrain);
1693
1694[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1695public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
1696
1697[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1698public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
1699
1700// =====================================================================================
1701// btCollisionWorld entries
1702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1703public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
1704
1705[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1706public static extern void UpdateAabbs2(IntPtr world);
1707
1708[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1709public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
1710
1711[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1712public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
1713
1714// =====================================================================================
1715// btDynamicsWorld entries
1716[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1717public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1718
1719[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1720public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1721
1722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1723public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj);
1724
1725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1726public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1727
1728[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1729public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
1730// =====================================================================================
1731// btCollisionObject entries
1732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1733public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
1734
1735[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1736public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
1737
1738[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1739public static extern bool HasAnisotripicFriction2(IntPtr constrain);
1740
1741[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1742public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
1743
1744[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1745public static extern float GetContactProcessingThreshold2(IntPtr obj);
1746
1747[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1748public static extern bool IsStaticObject2(IntPtr obj);
1749
1750[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1751public static extern bool IsKinematicObject2(IntPtr obj);
1752
1753[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1754public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
1755
1756[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1757public static extern bool HasContactResponse2(IntPtr obj);
1758
1759[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1760public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
1761
1762[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1763public static extern IntPtr GetCollisionShape2(IntPtr obj);
1764
1765[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1766public static extern int GetActivationState2(IntPtr obj);
1767
1768[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1769public static extern void SetActivationState2(IntPtr obj, int state);
1770
1771[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1772public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
1773
1774[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1775public static extern float GetDeactivationTime2(IntPtr obj);
1776
1777[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1778public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
1779
1780[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1781public static extern void Activate2(IntPtr obj, bool forceActivation);
1782
1783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1784public static extern bool IsActive2(IntPtr obj);
1785
1786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1787public static extern void SetRestitution2(IntPtr obj, float val);
1788
1789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1790public static extern float GetRestitution2(IntPtr obj);
1791
1792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1793public static extern void SetFriction2(IntPtr obj, float val);
1794
1795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1796public static extern float GetFriction2(IntPtr obj);
1797
1798 /* Haven't defined the type 'Transform'
1799[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1800public static extern Transform GetWorldTransform2(IntPtr obj);
1801
1802[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1803public static extern void setWorldTransform2(IntPtr obj, Transform trans);
1804 */
1805
1806[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1807public static extern Vector3 GetPosition2(IntPtr obj);
1808
1809[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1810public static extern Quaternion GetOrientation2(IntPtr obj);
1811
1812[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1813public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
1814
1815[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1816public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
1817
1818[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1819public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
1820
1821 /*
1822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1823public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
1824
1825[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1826public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
1827 */
1828
1829[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1830public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
1831
1832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1833public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
1834
1835[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1836public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
1837
1838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1839public static extern float GetHitFraction2(IntPtr obj);
1840
1841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1842public static extern void SetHitFraction2(IntPtr obj, float val);
1843
1844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1845public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1846
1847[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1848public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1849
1850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1851public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1852
1853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1854public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1855
1856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1857public static extern float GetCcdMotionThreshold2(IntPtr obj);
1858
1859[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1860public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
1861
1862[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1863public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
1864
1865[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1866public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
1867
1868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1869public static extern IntPtr GetUserPointer2(IntPtr obj);
1870
1871[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1872public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
1873
1874// =====================================================================================
1875// btRigidBody entries
1876[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1877public static extern void ApplyGravity2(IntPtr obj);
1878
1879[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1880public static extern void SetGravity2(IntPtr obj, Vector3 val);
1881
1882[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1883public static extern Vector3 GetGravity2(IntPtr obj);
1884
1885[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1886public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
1887
1888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1889public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
1890
1891[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1892public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
1893
1894[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1895public static extern float GetLinearDamping2(IntPtr obj);
1896
1897[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1898public static extern float GetAngularDamping2(IntPtr obj);
1899
1900[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1901public static extern float GetLinearSleepingThreshold2(IntPtr obj);
1902
1903[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1904public static extern float GetAngularSleepingThreshold2(IntPtr obj);
1905
1906[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1907public static extern void ApplyDamping2(IntPtr obj, float timeStep);
1908
1909[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1910public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
1911
1912[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1913public static extern Vector3 GetLinearFactor2(IntPtr obj);
1914
1915[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1916public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
1917
1918 /*
1919[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1920public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
1921 */
1922
1923[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1924public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
1925
1926// Add a force to the object as if its mass is one.
1927[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1928public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
1929
1930// Set the force being applied to the object as if its mass is one.
1931[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1932public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
1933
1934[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1935public static extern Vector3 GetTotalForce2(IntPtr obj);
1936
1937[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1938public static extern Vector3 GetTotalTorque2(IntPtr obj);
1939
1940[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1941public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
1942
1943[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1944public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
1945
1946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1947public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
1948
1949[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1950public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
1951
1952// Apply force at the given point. Will add torque to the object.
1953[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1954public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
1955
1956// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1957[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1958public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
1959
1960// Apply impulse to the object's torque. Force is scaled by object's mass.
1961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1962public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
1963
1964// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1965[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1966public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
1967
1968[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1969public static extern void ClearForces2(IntPtr obj);
1970
1971[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1972public static extern void ClearAllForces2(IntPtr obj);
1973
1974[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1975public static extern void UpdateInertiaTensor2(IntPtr obj);
1976
1977[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1978public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
1979
1980 /*
1981[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1982public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
1983 */
1984
1985[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1986public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1987
1988[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1989public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1990
1991[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1992public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1993
1994[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1995public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1996
1997[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1998public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1999
2000[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2001public static extern void Translate2(IntPtr obj, Vector3 trans);
2002
2003[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2004public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
2005
2006[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2007public static extern bool WantsSleeping2(IntPtr obj);
2008
2009[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2010public static extern void SetAngularFactor2(IntPtr obj, float factor);
2011
2012[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2013public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
2014
2015[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2016public static extern Vector3 GetAngularFactor2(IntPtr obj);
2017
2018[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2019public static extern bool IsInWorld2(IntPtr obj);
2020
2021[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2022public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
2023
2024[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2025public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
2026
2027[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2028public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
2029
2030[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2031public static extern int GetNumConstraintRefs2(IntPtr obj);
2032
2033[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2034public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
2035
2036// =====================================================================================
2037// btCollisionShape entries
2038
2039[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2040public static extern float GetAngularMotionDisc2(IntPtr shape);
2041
2042[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2043public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
2044
2045[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2046public static extern bool IsPolyhedral2(IntPtr shape);
2047
2048[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2049public static extern bool IsConvex2d2(IntPtr shape);
2050
2051[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2052public static extern bool IsConvex2(IntPtr shape);
2053
2054[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2055public static extern bool IsNonMoving2(IntPtr shape);
2056
2057[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2058public static extern bool IsConcave2(IntPtr shape);
2059
2060[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2061public static extern bool IsCompound2(IntPtr shape);
2062
2063[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2064public static extern bool IsSoftBody2(IntPtr shape);
2065
2066[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2067public static extern bool IsInfinite2(IntPtr shape);
2068
2069[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2070public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
2071
2072[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2073public static extern Vector3 GetLocalScaling2(IntPtr shape);
2074
2075[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2076public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
2077
2078[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2079public static extern int GetShapeType2(IntPtr shape);
2080
2081[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2082public static extern void SetMargin2(IntPtr shape, float val);
2083
2084[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2085public static extern float GetMargin2(IntPtr shape);
2086
2087// =====================================================================================
2088// Debugging
2089[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2090public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
2091
2092[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2093public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
2094
2095[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2096public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
2097
2098[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2099public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
2100
2101[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2102public static extern void DumpActivationInfo2(IntPtr sim);
2103
2104[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2105public static extern void DumpAllInfo2(IntPtr sim);
2106
2107[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2108public static extern void DumpPhysicsStatistics2(IntPtr sim);
2109
2110[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2111public static extern void ResetBroadphasePool(IntPtr sim);
2112
2113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2114public static extern void ResetConstraintSolver(IntPtr sim);
2115
2116}
2117
2118}
2119
2120}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
new file mode 100755
index 0000000..741f8db
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
@@ -0,0 +1,2589 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.IO;
30using System.Runtime.InteropServices;
31using System.Text;
32
33using OpenSim.Framework;
34
35using OpenMetaverse;
36
37using BulletXNA;
38using BulletXNA.LinearMath;
39using BulletXNA.BulletCollision;
40using BulletXNA.BulletDynamics;
41using BulletXNA.BulletCollision.CollisionDispatch;
42
43namespace OpenSim.Region.Physics.BulletSPlugin
44{
45public sealed class BSAPIXNA : BSAPITemplate
46{
47private sealed class BulletWorldXNA : BulletWorld
48{
49 public DiscreteDynamicsWorld world;
50 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
51 : base(id, physScene)
52 {
53 world = xx;
54 }
55}
56
57private sealed class BulletBodyXNA : BulletBody
58{
59 public CollisionObject body;
60 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
61
62 public BulletBodyXNA(uint id, CollisionObject xx)
63 : base(id)
64 {
65 body = xx;
66 }
67 public override bool HasPhysicalBody
68 {
69 get { return body != null; }
70 }
71 public override void Clear()
72 {
73 body = null;
74 }
75 public override string AddrString
76 {
77 get { return "XNARigidBody"; }
78 }
79}
80
81private sealed class BulletShapeXNA : BulletShape
82{
83 public CollisionShape shape;
84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
85 : base()
86 {
87 shape = xx;
88 shapeType = typ;
89 }
90 public override bool HasPhysicalShape
91 {
92 get { return shape != null; }
93 }
94 public override void Clear()
95 {
96 shape = null;
97 }
98 public override BulletShape Clone()
99 {
100 return new BulletShapeXNA(shape, shapeType);
101 }
102 public override bool ReferenceSame(BulletShape other)
103 {
104 BulletShapeXNA otheru = other as BulletShapeXNA;
105 return (otheru != null) && (this.shape == otheru.shape);
106
107 }
108 public override string AddrString
109 {
110 get { return "XNACollisionShape"; }
111 }
112}
113private sealed class BulletConstraintXNA : BulletConstraint
114{
115 public TypedConstraint constrain;
116 public BulletConstraintXNA(TypedConstraint xx) : base()
117 {
118 constrain = xx;
119 }
120
121 public override void Clear()
122 {
123 constrain = null;
124 }
125 public override bool HasPhysicalConstraint { get { return constrain != null; } }
126
127 // Used for log messages for a unique display of the memory/object allocated to this instance
128 public override string AddrString
129 {
130 get { return "XNAConstraint"; }
131 }
132}
133 internal int m_maxCollisions;
134 internal CollisionDesc[] UpdatedCollisions;
135 internal int LastCollisionDesc = 0;
136 internal int m_maxUpdatesPerFrame;
137 internal int LastEntityProperty = 0;
138
139 internal EntityProperties[] UpdatedObjects;
140 internal Dictionary<uint, GhostObject> specialCollisionObjects;
141
142 private static int m_collisionsThisFrame;
143 private BSScene PhysicsScene { get; set; }
144
145 public override string BulletEngineName { get { return "BulletXNA"; } }
146 public override string BulletEngineVersion { get; protected set; }
147
148 public BSAPIXNA(string paramName, BSScene physScene)
149 {
150 PhysicsScene = physScene;
151 }
152
153 /// <summary>
154 ///
155 /// </summary>
156 /// <param name="p"></param>
157 /// <param name="p_2"></param>
158 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
159 {
160 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
161 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
162 CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
163 if (body != null)
164 world.RemoveRigidBody(body);
165 else if (collisionObject != null)
166 world.RemoveCollisionObject(collisionObject);
167 else
168 return false;
169 return true;
170 }
171
172 public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody)
173 {
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
176 CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
177 if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null)
178 {
179 world.RemoveCollisionObject(collisionObject);
180 world.AddCollisionObject(collisionObject);
181 }
182 return true;
183 }
184
185 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
186 {
187 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
188 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
189 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
190
191 return true;
192
193 }
194
195 public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint)
196 {
197 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
198 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
199 world.RemoveConstraint(constraint);
200 return true;
201 }
202
203 public override void SetRestitution(BulletBody pCollisionObject, float pRestitution)
204 {
205 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
206 collisionObject.SetRestitution(pRestitution);
207 }
208
209 public override int GetShapeType(BulletShape pShape)
210 {
211 CollisionShape shape = (pShape as BulletShapeXNA).shape;
212 return (int)shape.GetShapeType();
213 }
214 public override void SetMargin(BulletShape pShape, float pMargin)
215 {
216 CollisionShape shape = (pShape as BulletShapeXNA).shape;
217 shape.SetMargin(pMargin);
218 }
219
220 public override float GetMargin(BulletShape pShape)
221 {
222 CollisionShape shape = (pShape as BulletShapeXNA).shape;
223 return shape.GetMargin();
224 }
225
226 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
227 {
228 CollisionShape shape = (pShape as BulletShapeXNA).shape;
229 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
230 shape.SetLocalScaling(ref vec);
231
232 }
233
234 public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold)
235 {
236 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
237 collisionObject.SetContactProcessingThreshold(contactprocessingthreshold);
238 }
239
240 public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold)
241 {
242 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
243 collisionObject.SetCcdMotionThreshold(pccdMotionThreashold);
244 }
245
246 public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius)
247 {
248 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
249 collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
250 }
251
252 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
253 {
254 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
255 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
256 }
257
258 public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
259 {
260 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
261 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
262 existingcollisionFlags |= pcollisionFlags;
263 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
264 return (CollisionFlags) (uint) existingcollisionFlags;
265 }
266
267 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
268 {
269 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
270 CollisionObject cbody = (pBody as BulletBodyXNA).body;
271 RigidBody rbody = cbody as RigidBody;
272
273 // Bullet resets several variables when an object is added to the world. In particular,
274 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
275 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
276 IndexedMatrix origPos = cbody.GetWorldTransform();
277 if (rbody != null)
278 {
279 IndexedVector3 origGrav = rbody.GetGravity();
280 world.AddRigidBody(rbody);
281 rbody.SetGravity(origGrav);
282 }
283 else
284 {
285 world.AddCollisionObject(cbody);
286 }
287 cbody.SetWorldTransform(origPos);
288
289 pBody.ApplyCollisionMask(pWorld.physicsScene);
290
291 //if (body.GetBroadphaseHandle() != null)
292 // world.UpdateSingleAabb(body);
293 return true;
294 }
295
296 public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState)
297 {
298 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
299 collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
300 }
301
302 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject)
303 {
304 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
305 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
306 world.UpdateSingleAabb(collisionObject);
307 }
308
309 public override void UpdateAabbs(BulletWorld pWorld) {
310 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
311 world.UpdateAabbs();
312 }
313 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
314 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
315 return world.GetForceUpdateAllAabbs();
316
317 }
318 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
319 {
320 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
321 world.SetForceUpdateAllAabbs(pForce);
322 }
323
324 public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask)
325 {
326 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
327 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
328 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
329 if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0)
330 return false;
331 return true;
332 }
333
334 public override void ClearAllForces(BulletBody pCollisionObject)
335 {
336 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
337 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
338 collisionObject.SetInterpolationLinearVelocity(ref zeroVector);
339 collisionObject.SetInterpolationAngularVelocity(ref zeroVector);
340 IndexedMatrix bodytransform = collisionObject.GetWorldTransform();
341
342 collisionObject.SetInterpolationWorldTransform(ref bodytransform);
343
344 if (collisionObject is RigidBody)
345 {
346 RigidBody rigidbody = collisionObject as RigidBody;
347 rigidbody.SetLinearVelocity(zeroVector);
348 rigidbody.SetAngularVelocity(zeroVector);
349 rigidbody.ClearForces();
350 }
351 }
352
353 public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3)
354 {
355 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
356 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
357 collisionObject.SetInterpolationAngularVelocity(ref vec);
358 }
359
360 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
361 {
362 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
363 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
364 body.SetAngularVelocity(ref vec);
365 }
366 public override Vector3 GetTotalForce(BulletBody pBody)
367 {
368 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
369 IndexedVector3 iv3 = body.GetTotalForce();
370 return new Vector3(iv3.X, iv3.Y, iv3.Z);
371 }
372 public override Vector3 GetTotalTorque(BulletBody pBody)
373 {
374 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
375 IndexedVector3 iv3 = body.GetTotalTorque();
376 return new Vector3(iv3.X, iv3.Y, iv3.Z);
377 }
378 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
379 {
380 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
381 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
382 return new Vector3(iv3.X, iv3.Y, iv3.Z);
383 }
384 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
385 {
386 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
387 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
388 body.SetInvInertiaDiagLocal(ref iv3);
389 }
390 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
391 {
392 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
393 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
394 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
395 body.ApplyForce(ref forceiv3, ref posiv3);
396 }
397 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
398 {
399 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
400 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
401 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
402 body.ApplyImpulse(ref impiv3, ref posiv3);
403 }
404
405 public override void ClearForces(BulletBody pBody)
406 {
407 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
408 body.ClearForces();
409 }
410
411 public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation)
412 {
413 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
414 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
415 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
416 _orientation.W);
417 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
418 mat._origin = vposition;
419 collisionObject.SetWorldTransform(mat);
420
421 }
422
423 public override Vector3 GetPosition(BulletBody pCollisionObject)
424 {
425 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
426 IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin;
427 return new Vector3(pos.X, pos.Y, pos.Z);
428 }
429
430 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
431 {
432 CollisionShape shape = (pShape as BulletShapeXNA).shape;
433 IndexedVector3 inertia = IndexedVector3.Zero;
434 shape.CalculateLocalInertia(pphysMass, out inertia);
435 return new Vector3(inertia.X, inertia.Y, inertia.Z);
436 }
437
438 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
439 {
440 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
441 if (body != null) // Can't set mass props on collision object.
442 {
443 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
444 body.SetMassProps(pphysMass, inertia);
445 }
446 }
447
448
449 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
450 {
451 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
452 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
453 body.SetTotalForce(ref force);
454 }
455
456 public override void SetFriction(BulletBody pCollisionObject, float _currentFriction)
457 {
458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
459 collisionObject.SetFriction(_currentFriction);
460 }
461
462 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
463 {
464 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
465 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
466 body.SetLinearVelocity(velocity);
467 }
468
469 public override void Activate(BulletBody pCollisionObject, bool pforceactivation)
470 {
471 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
472 collisionObject.Activate(pforceactivation);
473
474 }
475
476 public override Quaternion GetOrientation(BulletBody pCollisionObject)
477 {
478 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
479 IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation();
480 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
481 }
482
483 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
484 {
485 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
486 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
487 existingcollisionFlags &= ~pcollisionFlags;
488 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
489 return (CollisionFlags)(uint)existingcollisionFlags;
490 }
491
492 public override float GetCcdMotionThreshold(BulletBody pCollisionObject)
493 {
494 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
495 return collisionObject.GetCcdSquareMotionThreshold();
496 }
497
498 public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject)
499 {
500 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
501 return collisionObject.GetCcdSweptSphereRadius();
502
503 }
504
505 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
506 {
507 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
508 return (IntPtr)shape.GetUserPointer();
509 }
510
511 public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val)
512 {
513 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
514 shape.SetUserPointer(val);
515 }
516
517 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
518 {
519 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
520 if (body != null) // Can't set collisionobject.set gravity
521 {
522 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
523 body.SetGravity(gravity);
524 }
525 }
526
527 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
528 {
529 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
530 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
531 world.RemoveConstraint(constraint);
532 return true;
533 }
534
535 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
536 {
537 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
538 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
539 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
540 constraint.SetLinearLowerLimit(lowlimit);
541 constraint.SetLinearUpperLimit(highlimit);
542 return true;
543 }
544
545 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
546 {
547 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
548 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
549 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
550 constraint.SetAngularLowerLimit(lowlimit);
551 constraint.SetAngularUpperLimit(highlimit);
552 return true;
553 }
554
555 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
556 {
557 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
558 constraint.SetOverrideNumSolverIterations((int)cnt);
559 }
560
561 public override bool CalculateTransforms(BulletConstraint pConstraint)
562 {
563 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
564 constraint.CalculateTransforms();
565 return true;
566 }
567
568 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
569 {
570 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
571 constraint.SetEnabled((p_2 == 0) ? false : true);
572 }
573
574
575 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
576 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
577 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
578
579 {
580 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
581 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
582 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
583 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
584 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
585 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
586 frame1._origin = frame1v;
587
588 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
589 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
590 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
591 frame2._origin = frame1v;
592
593 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
594 puseLinearReferenceFrameA);
595 consttr.CalculateTransforms();
596 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
597
598 return new BulletConstraintXNA(consttr);
599 }
600
601 public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1,
602 Vector3 pframe1, Quaternion pframe1rot,
603 bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies)
604 {
605 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
606 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
607 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
608 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
609 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
610 frame1._origin = frame1v;
611
612 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB);
613 consttr.CalculateTransforms();
614 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
615
616 return new BulletConstraintXNA(consttr);
617 }
618
619 /// <summary>
620 ///
621 /// </summary>
622 /// <param name="pWorld"></param>
623 /// <param name="pBody1"></param>
624 /// <param name="pBody2"></param>
625 /// <param name="pjoinPoint"></param>
626 /// <param name="puseLinearReferenceFrameA"></param>
627 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
628 /// <returns></returns>
629 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
630 {
631 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
632 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
633 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
634 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
635 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
636
637 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
638 IndexedMatrix mat = IndexedMatrix.Identity;
639 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
640 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
641 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
642
643 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
644 consttr.CalculateTransforms();
645 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
646
647 return new BulletConstraintXNA(consttr);
648 }
649 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
650 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
651 {
652 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
653 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
654 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
655 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
656 frame1._origin = frame1v;
657
658 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
659 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
660 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
661 frame2._origin = frame2v;
662 constraint.SetFrames(ref frame1, ref frame2);
663 return true;
664 }
665
666 public override Vector3 GetLinearVelocity(BulletBody pBody)
667 {
668 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
669 IndexedVector3 iv3 = body.GetLinearVelocity();
670 return new Vector3(iv3.X, iv3.Y, iv3.Z);
671 }
672 public override Vector3 GetAngularVelocity(BulletBody pBody)
673 {
674 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
675 IndexedVector3 iv3 = body.GetAngularVelocity();
676 return new Vector3(iv3.X, iv3.Y, iv3.Z);
677 }
678 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
679 {
680 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
681 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
682 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
683 return new Vector3(iv3.X, iv3.Y, iv3.Z);
684 }
685 public override void Translate(BulletBody pCollisionObject, Vector3 trans)
686 {
687 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
688 collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z));
689 }
690 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
691 {
692 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
693 body.UpdateDeactivation(timeStep);
694 }
695
696 public override bool WantsSleeping(BulletBody pBody)
697 {
698 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
699 return body.WantsSleeping();
700 }
701
702 public override void SetAngularFactor(BulletBody pBody, float factor)
703 {
704 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
705 body.SetAngularFactor(factor);
706 }
707
708 public override Vector3 GetAngularFactor(BulletBody pBody)
709 {
710 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
711 IndexedVector3 iv3 = body.GetAngularFactor();
712 return new Vector3(iv3.X, iv3.Y, iv3.Z);
713 }
714
715 public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject)
716 {
717 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
718 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
719 return world.IsInWorld(collisionObject);
720 }
721
722 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
723 {
724 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
725 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
726 body.AddConstraintRef(constrain);
727 }
728
729 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
730 {
731 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
732 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
733 body.RemoveConstraintRef(constrain);
734 }
735
736 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
737 {
738 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
739 return new BulletConstraintXNA(body.GetConstraintRef(index));
740 }
741
742 public override int GetNumConstraintRefs(BulletBody pBody)
743 {
744 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
745 return body.GetNumConstraintRefs();
746 }
747
748 public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity)
749 {
750 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
751 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
752 collisionObject.SetInterpolationLinearVelocity(ref velocity);
753 }
754
755 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
756 {
757 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
758 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
759 return true;
760 }
761 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
762 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
763 {
764 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
765 constraint.SetBreakingImpulseThreshold(threshold);
766 return true;
767 }
768 public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation)
769 {
770 HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint;
771 if (softness == HINGE_NOT_SPECIFIED)
772 constraint.SetLimit(low, high);
773 else
774 constraint.SetLimit(low, high, softness, bias, relaxation);
775 return true;
776 }
777 public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse)
778 {
779 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
780 constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true));
781 return true;
782 }
783
784 public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint)
785 {
786 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
787 if (index == SPRING_NOT_SPECIFIED)
788 {
789 constraint.SetEquilibriumPoint();
790 }
791 else
792 {
793 if (equilibriumPoint == SPRING_NOT_SPECIFIED)
794 constraint.SetEquilibriumPoint(index);
795 else
796 constraint.SetEquilibriumPoint(index, equilibriumPoint);
797 }
798 return true;
799 }
800
801 public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness)
802 {
803 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
804 constraint.SetStiffness(index, stiffness);
805 return true;
806 }
807
808 public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping)
809 {
810 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
811 constraint.SetDamping(index, damping);
812 return true;
813 }
814
815 public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val)
816 {
817 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
818 switch (lowerUpper)
819 {
820 case SLIDER_LOWER_LIMIT:
821 switch (linAng)
822 {
823 case SLIDER_LINEAR:
824 constraint.SetLowerLinLimit(val);
825 break;
826 case SLIDER_ANGULAR:
827 constraint.SetLowerAngLimit(val);
828 break;
829 }
830 break;
831 case SLIDER_UPPER_LIMIT:
832 switch (linAng)
833 {
834 case SLIDER_LINEAR:
835 constraint.SetUpperLinLimit(val);
836 break;
837 case SLIDER_ANGULAR:
838 constraint.SetUpperAngLimit(val);
839 break;
840 }
841 break;
842 }
843 return true;
844 }
845 public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val)
846 {
847 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
848 switch (softRestDamp)
849 {
850 case SLIDER_SET_SOFTNESS:
851 switch (dirLimOrtho)
852 {
853 case SLIDER_SET_DIRECTION:
854 switch (linAng)
855 {
856 case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break;
857 case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break;
858 }
859 break;
860 case SLIDER_SET_LIMIT:
861 switch (linAng)
862 {
863 case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break;
864 case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break;
865 }
866 break;
867 case SLIDER_SET_ORTHO:
868 switch (linAng)
869 {
870 case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break;
871 case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break;
872 }
873 break;
874 }
875 break;
876 case SLIDER_SET_RESTITUTION:
877 switch (dirLimOrtho)
878 {
879 case SLIDER_SET_DIRECTION:
880 switch (linAng)
881 {
882 case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break;
883 case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break;
884 }
885 break;
886 case SLIDER_SET_LIMIT:
887 switch (linAng)
888 {
889 case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break;
890 case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break;
891 }
892 break;
893 case SLIDER_SET_ORTHO:
894 switch (linAng)
895 {
896 case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break;
897 case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break;
898 }
899 break;
900 }
901 break;
902 case SLIDER_SET_DAMPING:
903 switch (dirLimOrtho)
904 {
905 case SLIDER_SET_DIRECTION:
906 switch (linAng)
907 {
908 case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break;
909 case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break;
910 }
911 break;
912 case SLIDER_SET_LIMIT:
913 switch (linAng)
914 {
915 case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break;
916 case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break;
917 }
918 break;
919 case SLIDER_SET_ORTHO:
920 switch (linAng)
921 {
922 case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break;
923 case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break;
924 }
925 break;
926 }
927 break;
928 }
929 return true;
930 }
931 public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse)
932 {
933 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
934 switch (linAng)
935 {
936 case SLIDER_LINEAR:
937 constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true);
938 break;
939 case SLIDER_ANGULAR:
940 constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true);
941 break;
942 }
943 return true;
944 }
945 public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val)
946 {
947 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
948 switch (forceVel)
949 {
950 case SLIDER_MOTOR_VELOCITY:
951 switch (linAng)
952 {
953 case SLIDER_LINEAR:
954 constraint.SetTargetLinMotorVelocity(val);
955 break;
956 case SLIDER_ANGULAR:
957 constraint.SetTargetAngMotorVelocity(val);
958 break;
959 }
960 break;
961 case SLIDER_MAX_MOTOR_FORCE:
962 switch (linAng)
963 {
964 case SLIDER_LINEAR:
965 constraint.SetMaxLinMotorForce(val);
966 break;
967 case SLIDER_ANGULAR:
968 constraint.SetMaxAngMotorForce(val);
969 break;
970 }
971 break;
972 }
973 return true;
974 }
975
976 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
977 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
978 {
979 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
980 float lineardamping = body.GetLinearDamping();
981 body.SetDamping(lineardamping, angularDamping);
982
983 }
984
985 public override void UpdateInertiaTensor(BulletBody pBody)
986 {
987 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
988 if (body != null) // can't update inertia tensor on CollisionObject
989 body.UpdateInertiaTensor();
990 }
991
992 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
993 {
994 CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
995 shape.RecalculateLocalAabb();
996 }
997
998 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
999 public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject)
1000 {
1001 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1002 uint flags = (uint)collisionObject.GetCollisionFlags();
1003 return (CollisionFlags) flags;
1004 }
1005
1006 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
1007 {
1008 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1009 body.SetDamping(pLinear, pAngular);
1010 }
1011 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
1012 public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime)
1013 {
1014 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1015 collisionObject.SetDeactivationTime(pDeactivationTime);
1016 }
1017 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
1018 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
1019 {
1020 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1021 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
1022 }
1023
1024 public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject)
1025 {
1026 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1027 return (CollisionObjectTypes)(int) collisionObject.GetInternalType();
1028 }
1029
1030 public override void ApplyGravity(BulletBody pBody)
1031 {
1032
1033 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1034 body.ApplyGravity();
1035 }
1036
1037 public override Vector3 GetGravity(BulletBody pBody)
1038 {
1039 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1040 IndexedVector3 gravity = body.GetGravity();
1041 return new Vector3(gravity.X, gravity.Y, gravity.Z);
1042 }
1043
1044 public override void SetLinearDamping(BulletBody pBody, float lin_damping)
1045 {
1046 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1047 float angularDamping = body.GetAngularDamping();
1048 body.SetDamping(lin_damping, angularDamping);
1049 }
1050
1051 public override float GetLinearDamping(BulletBody pBody)
1052 {
1053 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1054 return body.GetLinearDamping();
1055 }
1056
1057 public override float GetAngularDamping(BulletBody pBody)
1058 {
1059 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1060 return body.GetAngularDamping();
1061 }
1062
1063 public override float GetLinearSleepingThreshold(BulletBody pBody)
1064 {
1065 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1066 return body.GetLinearSleepingThreshold();
1067 }
1068
1069 public override void ApplyDamping(BulletBody pBody, float timeStep)
1070 {
1071 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1072 body.ApplyDamping(timeStep);
1073 }
1074
1075 public override Vector3 GetLinearFactor(BulletBody pBody)
1076 {
1077 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1078 IndexedVector3 linearFactor = body.GetLinearFactor();
1079 return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z);
1080 }
1081
1082 public override void SetLinearFactor(BulletBody pBody, Vector3 factor)
1083 {
1084 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1085 body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z));
1086 }
1087
1088 public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot)
1089 {
1090 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1091 IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W);
1092 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat);
1093 mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z);
1094 body.SetCenterOfMassTransform( ref mat);
1095 /* TODO: double check this */
1096 }
1097
1098 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
1099 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
1100 {
1101 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1102 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1103 body.ApplyCentralForce(ref fSum);
1104 }
1105 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
1106 {
1107 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1108 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1109 body.ApplyCentralImpulse(ref fSum);
1110 }
1111 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
1112 {
1113 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1114 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1115 body.ApplyTorque(ref fSum);
1116 }
1117 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
1118 {
1119 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1120 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1121 body.ApplyTorqueImpulse(ref fSum);
1122 }
1123
1124 public override void DestroyObject(BulletWorld pWorld, BulletBody pBody)
1125 {
1126 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1127 CollisionObject co = (pBody as BulletBodyXNA).rigidBody;
1128 RigidBody bo = co as RigidBody;
1129 if (bo == null)
1130 {
1131
1132 if (world.IsInWorld(co))
1133 {
1134 world.RemoveCollisionObject(co);
1135 }
1136 }
1137 else
1138 {
1139
1140 if (world.IsInWorld(bo))
1141 {
1142 world.RemoveRigidBody(bo);
1143 }
1144 }
1145 if (co != null)
1146 {
1147 if (co.GetUserPointer() != null)
1148 {
1149 uint localId = (uint) co.GetUserPointer();
1150 if (specialCollisionObjects.ContainsKey(localId))
1151 {
1152 specialCollisionObjects.Remove(localId);
1153 }
1154 }
1155 }
1156
1157 }
1158
1159 public override void Shutdown(BulletWorld pWorld)
1160 {
1161 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1162 world.Cleanup();
1163 }
1164
1165 public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id)
1166 {
1167 CollisionShape shape1 = (pShape as BulletShapeXNA).shape;
1168
1169 // TODO: Turn this from a reference copy to a Value Copy.
1170 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
1171
1172 return shape2;
1173 }
1174
1175 public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape)
1176 {
1177 //TODO:
1178 return false;
1179 }
1180 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1181
1182 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1183 {
1184 CollisionWorld world = (pWorld as BulletWorldXNA).world;
1185 IndexedMatrix mat =
1186 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
1187 pRawOrientation.Z, pRawOrientation.W));
1188 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1189 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1190 //UpdateSingleAabb(world, shape);
1191 // TODO: Feed Update array into null
1192 SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null);
1193 RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero);
1194 RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero)
1195 {
1196 m_mass = 0
1197 };
1198 /*
1199 m_mass = mass;
1200 m_motionState =motionState;
1201 m_collisionShape = collisionShape;
1202 m_localInertia = localInertia;
1203 m_linearDamping = 0f;
1204 m_angularDamping = 0f;
1205 m_friction = 0.5f;
1206 m_restitution = 0f;
1207 m_linearSleepingThreshold = 0.8f;
1208 m_angularSleepingThreshold = 1f;
1209 m_additionalDamping = false;
1210 m_additionalDampingFactor = 0.005f;
1211 m_additionalLinearDampingThresholdSqr = 0.01f;
1212 m_additionalAngularDampingThresholdSqr = 0.01f;
1213 m_additionalAngularDampingFactor = 0.01f;
1214 m_startWorldTransform = IndexedMatrix.Identity;
1215 */
1216 body.SetUserPointer(pLocalID);
1217
1218 return new BulletBodyXNA(pLocalID, body);
1219 }
1220
1221
1222 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1223 {
1224
1225 IndexedMatrix mat =
1226 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
1227 pRawOrientation.Z, pRawOrientation.W));
1228 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1229
1230 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1231
1232 // TODO: Feed Update array into null
1233 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
1234 body.SetWorldTransform(mat);
1235 body.SetUserPointer(pLocalID);
1236 return new BulletBodyXNA(pLocalID, body);
1237 }
1238 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
1239 public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags)
1240 {
1241 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1242 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
1243 return (CollisionFlags)collisionObject.GetCollisionFlags();
1244 }
1245
1246 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
1247 {
1248
1249 /* TODO */
1250 return Vector3.Zero;
1251 }
1252 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
1253 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
1254 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
1255 public override bool IsStaticObject(BulletBody pCollisionObject)
1256 {
1257 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1258 return collisionObject.IsStaticObject();
1259
1260 }
1261 public override bool IsKinematicObject(BulletBody pCollisionObject)
1262 {
1263 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1264 return collisionObject.IsKinematicObject();
1265 }
1266 public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject)
1267 {
1268 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1269 return collisionObject.IsStaticOrKinematicObject();
1270 }
1271 public override bool HasContactResponse(BulletBody pCollisionObject)
1272 {
1273 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1274 return collisionObject.HasContactResponse();
1275 }
1276 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
1277 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
1278 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
1279 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
1280 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
1281 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
1282 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
1283 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
1284
1285 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
1286 public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction)
1287 {
1288 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1289 collisionObject.SetHitFraction(pHitFraction);
1290 }
1291 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
1292 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
1293 {
1294 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1295 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
1296 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
1297 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
1298 capsuleShapeZ.SetLocalScaling(ref scale);
1299
1300 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
1301 }
1302
1303 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
1304 int maxCollisions, ref CollisionDesc[] collisionArray,
1305 int maxUpdates, ref EntityProperties[] updateArray
1306 )
1307 {
1308
1309 UpdatedObjects = updateArray;
1310 UpdatedCollisions = collisionArray;
1311 /* TODO */
1312 ConfigurationParameters[] configparms = new ConfigurationParameters[1];
1313 configparms[0] = parms;
1314 Vector3 worldExtent = maxPosition;
1315 m_maxCollisions = maxCollisions;
1316 m_maxUpdatesPerFrame = maxUpdates;
1317 specialCollisionObjects = new Dictionary<uint, GhostObject>();
1318
1319 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1320 }
1321
1322 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1323 ConfigurationParameters[] o,
1324 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1325 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1326 object mDebugLogCallbackHandle)
1327 {
1328 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
1329
1330 p.angularDamping = BSParam.AngularDamping;
1331 p.defaultFriction = o[0].defaultFriction;
1332 p.defaultFriction = o[0].defaultFriction;
1333 p.defaultDensity = o[0].defaultDensity;
1334 p.defaultRestitution = o[0].defaultRestitution;
1335 p.collisionMargin = o[0].collisionMargin;
1336 p.gravity = o[0].gravity;
1337
1338 p.linearDamping = BSParam.LinearDamping;
1339 p.angularDamping = BSParam.AngularDamping;
1340 p.deactivationTime = BSParam.DeactivationTime;
1341 p.linearSleepingThreshold = BSParam.LinearSleepingThreshold;
1342 p.angularSleepingThreshold = BSParam.AngularSleepingThreshold;
1343 p.ccdMotionThreshold = BSParam.CcdMotionThreshold;
1344 p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius;
1345 p.contactProcessingThreshold = BSParam.ContactProcessingThreshold;
1346
1347 p.terrainImplementation = BSParam.TerrainImplementation;
1348 p.terrainFriction = BSParam.TerrainFriction;
1349
1350 p.terrainHitFraction = BSParam.TerrainHitFraction;
1351 p.terrainRestitution = BSParam.TerrainRestitution;
1352 p.terrainCollisionMargin = BSParam.TerrainCollisionMargin;
1353
1354 p.avatarFriction = BSParam.AvatarFriction;
1355 p.avatarStandingFriction = BSParam.AvatarStandingFriction;
1356 p.avatarDensity = BSParam.AvatarDensity;
1357 p.avatarRestitution = BSParam.AvatarRestitution;
1358 p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth;
1359 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
1360 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
1361 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
1362
1363 p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
1364
1365 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1366 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1367 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
1368 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
1369 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
1370 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
1371 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
1372 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
1373
1374 p.linksetImplementation = BSParam.LinksetImplementation;
1375 p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset);
1376 p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor);
1377 p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
1378 p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
1379 p.linkConstraintERP = BSParam.LinkConstraintERP;
1380 p.linkConstraintCFM = BSParam.LinkConstraintCFM;
1381 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
1382 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
1383 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1384
1385 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1386 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1387
1388
1389 if (p.maxPersistantManifoldPoolSize > 0)
1390 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
1391 if (p.shouldDisableContactPoolDynamicAllocation !=0)
1392 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
1393 //if (p.maxCollisionAlgorithmPoolSize >0 )
1394
1395 DbvtBroadphase m_broadphase = new DbvtBroadphase();
1396 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
1397 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
1398
1399 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
1400 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
1401
1402 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
1403
1404 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
1405
1406 world.LastCollisionDesc = 0;
1407 world.LastEntityProperty = 0;
1408
1409 world.WorldSettings.Params = p;
1410 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
1411 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
1412 if (p.shouldRandomizeSolverOrder != 0)
1413 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
1414
1415 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
1416 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
1417
1418 if (p.shouldEnableFrictionCaching != 0)
1419 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1420
1421 if (p.numberOfSolverIterations > 0)
1422 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
1423
1424
1425 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
1426 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
1427 world.GetSolverInfo().m_globalCfm = 0.0f;
1428 world.GetSolverInfo().m_tau = 0.6f;
1429 world.GetSolverInfo().m_friction = 0.3f;
1430 world.GetSolverInfo().m_maxErrorReduction = 20f;
1431 world.GetSolverInfo().m_numIterations = 10;
1432 world.GetSolverInfo().m_erp = 0.2f;
1433 world.GetSolverInfo().m_erp2 = 0.1f;
1434 world.GetSolverInfo().m_sor = 1.0f;
1435 world.GetSolverInfo().m_splitImpulse = false;
1436 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1437 world.GetSolverInfo().m_linearSlop = 0.0f;
1438 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1439 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1440 world.SetForceUpdateAllAabbs(true);
1441
1442 //BSParam.TerrainImplementation = 0;
1443 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1444
1445 // Turn off Pooling since globals and pooling are bad for threading.
1446 BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false);
1447 BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false);
1448 BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false);
1449 BulletGlobals.CastResultPool.SetPoolingEnabled(false);
1450 BulletGlobals.SphereShapePool.SetPoolingEnabled(false);
1451 BulletGlobals.DbvtNodePool.SetPoolingEnabled(false);
1452 BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false);
1453 BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false);
1454 BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false);
1455 BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false);
1456 BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false);
1457 BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false);
1458 BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false);
1459 BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false);
1460 BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false);
1461 BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false);
1462
1463 BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
1464 BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false);
1465 BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false);
1466 BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false);
1467 BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false);
1468 BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
1469 BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false);
1470 BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false);
1471 BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false);
1472 BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false);
1473 BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false);
1474 BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false);
1475 BulletGlobals.GJKPool.SetPoolingEnabled(false);
1476 BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false);
1477 BulletGlobals.TriangleShapePool.SetPoolingEnabled(false);
1478 BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false);
1479 BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false);
1480 BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false);
1481 BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false);
1482 BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false);
1483 BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false);
1484 BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false);
1485 BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false);
1486 BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false);
1487 BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false);
1488
1489 return world;
1490 }
1491 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1492 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1493 {
1494 Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
1495 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1496 {
1497 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1498 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1499 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1500 }
1501 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1502 {
1503 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1504 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1505 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1506 }
1507 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1508 {
1509 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1510 }
1511 return true;
1512 }
1513
1514 public override bool PushUpdate(BulletBody pCollisionObject)
1515 {
1516 bool ret = false;
1517 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1518 RigidBody rb = collisionObject as RigidBody;
1519 if (rb != null)
1520 {
1521 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1522 if (sms != null)
1523 {
1524 IndexedMatrix wt = IndexedMatrix.Identity;
1525 sms.GetWorldTransform(out wt);
1526 sms.SetWorldTransform(ref wt, true);
1527 ret = true;
1528 }
1529 }
1530 return ret;
1531
1532 }
1533
1534 public override float GetAngularMotionDisc(BulletShape pShape)
1535 {
1536 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1537 return shape.GetAngularMotionDisc();
1538 }
1539 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1540 {
1541 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1542 return shape.GetContactBreakingThreshold(defaultFactor);
1543 }
1544 public override bool IsCompound(BulletShape pShape)
1545 {
1546 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1547 return shape.IsCompound();
1548 }
1549 public override bool IsSoftBody(BulletShape pShape)
1550 {
1551 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1552 return shape.IsSoftBody();
1553 }
1554 public override bool IsPolyhedral(BulletShape pShape)
1555 {
1556 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1557 return shape.IsPolyhedral();
1558 }
1559 public override bool IsConvex2d(BulletShape pShape)
1560 {
1561 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1562 return shape.IsConvex2d();
1563 }
1564 public override bool IsConvex(BulletShape pShape)
1565 {
1566 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1567 return shape.IsConvex();
1568 }
1569 public override bool IsNonMoving(BulletShape pShape)
1570 {
1571 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1572 return shape.IsNonMoving();
1573 }
1574 public override bool IsConcave(BulletShape pShape)
1575 {
1576 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1577 return shape.IsConcave();
1578 }
1579 public override bool IsInfinite(BulletShape pShape)
1580 {
1581 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1582 return shape.IsInfinite();
1583 }
1584 public override bool IsNativeShape(BulletShape pShape)
1585 {
1586 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1587 bool ret;
1588 switch (shape.GetShapeType())
1589 {
1590 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1591 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1592 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1593 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1594 ret = true;
1595 break;
1596 default:
1597 ret = false;
1598 break;
1599 }
1600 return ret;
1601 }
1602
1603 public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin)
1604 {
1605 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1606 shape.SetMargin(pMargin);
1607 }
1608
1609 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1610 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1611 {
1612 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1613 IndexedMatrix bodyTransform = new IndexedMatrix();
1614 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1615 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1616 GhostObject gObj = new PairCachingGhostObject();
1617 gObj.SetWorldTransform(bodyTransform);
1618 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1619 gObj.SetCollisionShape(shape);
1620 gObj.SetUserPointer(pLocalID);
1621
1622 if (specialCollisionObjects.ContainsKey(pLocalID))
1623 specialCollisionObjects[pLocalID] = gObj;
1624 else
1625 specialCollisionObjects.Add(pLocalID, gObj);
1626
1627 // TODO: Add to Special CollisionObjects!
1628 return new BulletBodyXNA(pLocalID, gObj);
1629 }
1630
1631 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape)
1632 {
1633 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1634 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1635 if (pShape == null)
1636 {
1637 collisionObject.SetCollisionShape(new EmptyShape());
1638 }
1639 else
1640 {
1641 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1642 collisionObject.SetCollisionShape(shape);
1643 }
1644 }
1645 public override BulletShape GetCollisionShape(BulletBody pCollisionObject)
1646 {
1647 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1648 CollisionShape shape = collisionObject.GetCollisionShape();
1649 return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1650 }
1651
1652 //(PhysicsScene.World.ptr, nativeShapeData)
1653 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1654 {
1655 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1656 CollisionShape shape = null;
1657 switch (pShapeData.Type)
1658 {
1659 case BSPhysicsShapeType.SHAPE_BOX:
1660 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1661 break;
1662 case BSPhysicsShapeType.SHAPE_CONE:
1663 shape = new ConeShapeZ(0.5f, 1.0f);
1664 break;
1665 case BSPhysicsShapeType.SHAPE_CYLINDER:
1666 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1667 break;
1668 case BSPhysicsShapeType.SHAPE_SPHERE:
1669 shape = new SphereShape(0.5f);
1670 break;
1671
1672 }
1673 if (shape != null)
1674 {
1675 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1676 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1677 shape.SetLocalScaling(ref scaling);
1678
1679 }
1680 return new BulletShapeXNA(shape, pShapeData.Type);
1681 }
1682 //PhysicsScene.World.ptr, false
1683 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1684 {
1685 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1686 }
1687
1688 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1689 {
1690 CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
1691 return compoundshape.GetNumChildShapes();
1692 }
1693 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1694 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1695 {
1696 IndexedMatrix relativeTransform = new IndexedMatrix();
1697 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1698 CollisionShape addshape = (paddShape as BulletShapeXNA).shape;
1699
1700 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1701 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1702 compoundshape.AddChildShape(ref relativeTransform, addshape);
1703
1704 }
1705
1706 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1707 {
1708 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1709 CollisionShape ret = null;
1710 ret = compoundshape.GetChildShape(pii);
1711 compoundshape.RemoveChildShapeByIndex(pii);
1712 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
1713 }
1714
1715 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
1716
1717 if (cShape == null)
1718 return null;
1719 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
1720 CollisionShape shape = compoundShape.GetChildShape(indx);
1721 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1722
1723
1724 return retShape;
1725 }
1726
1727 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
1728 {
1729 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1730 switch (pin)
1731 {
1732 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1733 ret = BSPhysicsShapeType.SHAPE_BOX;
1734 break;
1735 case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE:
1736 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1737 break;
1738
1739 case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE:
1740 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1741 break;
1742 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE:
1743 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1744 break;
1745 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE:
1746 ret = BSPhysicsShapeType.SHAPE_HULL;
1747 break;
1748 case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE:
1749 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1750 break;
1751 case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE:
1752 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1753 break;
1754 //implicit convex shapes
1755 case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE:
1756 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1757 break;
1758 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1759 ret = BSPhysicsShapeType.SHAPE_SPHERE;
1760 break;
1761 case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE:
1762 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1763 break;
1764 case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE:
1765 ret = BSPhysicsShapeType.SHAPE_CAPSULE;
1766 break;
1767 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1768 ret = BSPhysicsShapeType.SHAPE_CONE;
1769 break;
1770 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE:
1771 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1772 break;
1773 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1774 ret = BSPhysicsShapeType.SHAPE_CYLINDER;
1775 break;
1776 case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE:
1777 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1778 break;
1779 case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE:
1780 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1781 break;
1782 case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE:
1783 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1784 break;
1785 case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE:
1786 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1787 break;
1788 case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE:
1789 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1790 break;
1791 case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE:
1792 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1793 break;
1794 //concave shape
1795 case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE:
1796 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1797 break;
1798 //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy!
1799 case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE:
1800 ret = BSPhysicsShapeType.SHAPE_MESH;
1801 break;
1802 case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE:
1803 ret = BSPhysicsShapeType.SHAPE_MESH;
1804 break;
1805 ///used for demo integration FAST/Swift collision library and Bullet
1806 case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE:
1807 ret = BSPhysicsShapeType.SHAPE_MESH;
1808 break;
1809 //terrain
1810 case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE:
1811 ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP;
1812 break;
1813 ///Used for GIMPACT Trimesh integration
1814 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE:
1815 ret = BSPhysicsShapeType.SHAPE_GIMPACT;
1816 break;
1817 ///Multimaterial mesh
1818 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE:
1819 ret = BSPhysicsShapeType.SHAPE_MESH;
1820 break;
1821
1822 case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE:
1823 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1824 break;
1825 case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE:
1826 ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE;
1827 break;
1828 case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE:
1829 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1830 break;
1831 case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE:
1832 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1833 break;
1834
1835 case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE:
1836 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
1837 break;
1838
1839 case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE:
1840 ret = BSPhysicsShapeType.SHAPE_MESH;
1841 break;
1842 case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE:
1843 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1844 break;
1845 case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE:
1846 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1847 break;
1848 case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE:
1849 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1850 break;
1851 }
1852 return ret;
1853 }
1854
1855 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1856 public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ }
1857
1858 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1859 {
1860 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1861 m_planeshape.SetMargin(pcollisionMargin);
1862 m_planeshape.SetUserPointer(pLocalId);
1863 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1864 }
1865
1866 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1867 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
1868 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1869
1870 {
1871 Generic6DofSpringConstraint constrain = null;
1872 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1873 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
1874 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
1875 if (body1 != null && body2 != null)
1876 {
1877 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1878 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1879 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1880 frame1._origin = frame1v;
1881
1882 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1883 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1884 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1885 frame2._origin = frame1v;
1886
1887 constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1888 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1889
1890 constrain.CalculateTransforms();
1891 }
1892
1893 return new BulletConstraintXNA(constrain);
1894 }
1895
1896 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1897 Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB,
1898 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1899 {
1900 HingeConstraint constrain = null;
1901 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1902 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1903 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1904 if (rb1 != null && rb2 != null)
1905 {
1906 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1907 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1908 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1909 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1910 constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA);
1911 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1912 }
1913 return new BulletConstraintXNA(constrain);
1914 }
1915
1916 public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1917 Vector3 pframe1, Quaternion pframe1rot,
1918 Vector3 pframe2, Quaternion pframe2rot,
1919 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1920 {
1921 SliderConstraint constrain = null;
1922 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1923 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1924 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1925 if (rb1 != null && rb2 != null)
1926 {
1927 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1928 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1929 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1930 frame1._origin = frame1v;
1931
1932 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1933 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1934 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1935 frame2._origin = frame1v;
1936
1937 constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1938 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1939 }
1940 return new BulletConstraintXNA(constrain);
1941 }
1942
1943 public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1944 Vector3 pframe1, Quaternion pframe1rot,
1945 Vector3 pframe2, Quaternion pframe2rot,
1946 bool pdisableCollisionsBetweenLinkedBodies)
1947 {
1948 ConeTwistConstraint constrain = null;
1949 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1950 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1951 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1952 if (rb1 != null && rb2 != null)
1953 {
1954 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1955 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1956 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1957 frame1._origin = frame1v;
1958
1959 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1960 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1961 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1962 frame2._origin = frame1v;
1963
1964 constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2);
1965 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1966 }
1967 return new BulletConstraintXNA(constrain);
1968 }
1969
1970 public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1971 Vector3 paxisInA, Vector3 paxisInB,
1972 float pratio, bool pdisableCollisionsBetweenLinkedBodies)
1973 {
1974 Generic6DofConstraint constrain = null;
1975 /* BulletXNA does not have a gear constraint
1976 GearConstraint constrain = null;
1977 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1978 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1979 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1980 if (rb1 != null && rb2 != null)
1981 {
1982 IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1983 IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1984 constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio);
1985 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1986 }
1987 */
1988 return new BulletConstraintXNA(constrain);
1989 }
1990
1991 public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1992 Vector3 ppivotInA, Vector3 ppivotInB,
1993 bool pdisableCollisionsBetweenLinkedBodies)
1994 {
1995 Point2PointConstraint constrain = null;
1996 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1997 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1998 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1999 if (rb1 != null && rb2 != null)
2000 {
2001 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
2002 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
2003 constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB);
2004 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
2005 }
2006 return new BulletConstraintXNA(constrain);
2007 }
2008
2009 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
2010 {
2011 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2012 CompoundShape compoundshape = new CompoundShape(false);
2013
2014 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
2015 int ii = 1;
2016
2017 for (int i = 0; i < pHullCount; i++)
2018 {
2019 int vertexCount = (int) pConvHulls[ii];
2020
2021 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
2022 IndexedMatrix childTrans = IndexedMatrix.Identity;
2023 childTrans._origin = centroid;
2024
2025 List<IndexedVector3> virts = new List<IndexedVector3>();
2026 int ender = ((ii + 4) + (vertexCount*3));
2027 for (int iii = ii + 4; iii < ender; iii+=3)
2028 {
2029
2030 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
2031 }
2032 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
2033 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
2034 compoundshape.AddChildShape(ref childTrans, convexShape);
2035 ii += (vertexCount*3 + 4);
2036 }
2037
2038 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
2039 }
2040
2041 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
2042 {
2043 /* TODO */ return null;
2044 }
2045
2046 public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
2047 {
2048 /* TODO */ return null;
2049 }
2050
2051 public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2052 {
2053 /* TODO */ return null;
2054 }
2055
2056 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2057 {
2058 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
2059
2060 for (int iter = 0; iter < pVerticesCount; iter++)
2061 {
2062 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
2063 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
2064 }
2065
2066 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
2067 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
2068 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
2069 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2070 IndexedMesh mesh = new IndexedMesh();
2071 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2072 mesh.m_numTriangles = pIndicesCount/3;
2073 mesh.m_numVertices = pVerticesCount;
2074 mesh.m_triangleIndexBase = indicesarr;
2075 mesh.m_vertexBase = vertices;
2076 mesh.m_vertexStride = 3;
2077 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2078 mesh.m_triangleIndexStride = 3;
2079
2080 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2081 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2082 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
2083 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
2084 // world.UpdateSingleAabb(meshShape);
2085 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
2086
2087 }
2088 public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2089 {
2090 // TODO:
2091 return null;
2092 }
2093 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
2094 {
2095
2096 String fileName = "objTest3.raw";
2097 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
2098 StreamWriter sw = new StreamWriter(completePath);
2099 IndexedMesh mesh = new IndexedMesh();
2100
2101 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2102 mesh.m_numTriangles = pIndicesCount / 3;
2103 mesh.m_numVertices = pVerticesCount;
2104 mesh.m_triangleIndexBase = indices;
2105 mesh.m_vertexBase = vertices;
2106 mesh.m_vertexStride = 3;
2107 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2108 mesh.m_triangleIndexStride = 3;
2109
2110 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2111 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2112
2113
2114
2115 for (int i = 0; i < pVerticesCount; i++)
2116 {
2117
2118 string s = vertices[indices[i * 3]].ToString("0.0000");
2119 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
2120 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
2121
2122 sw.Write(s + "\n");
2123 }
2124
2125 sw.Close();
2126 }
2127 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
2128 {
2129
2130 String fileName = "objTest6.raw";
2131 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
2132 StreamWriter sw = new StreamWriter(completePath);
2133 IndexedMesh mesh = new IndexedMesh();
2134
2135 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2136 mesh.m_numTriangles = pIndicesCount / 3;
2137 mesh.m_numVertices = pVerticesCount;
2138 mesh.m_triangleIndexBase = indices;
2139 mesh.m_vertexBase = vertices;
2140 mesh.m_vertexStride = 3;
2141 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2142 mesh.m_triangleIndexStride = 3;
2143
2144 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2145 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2146
2147
2148 sw.WriteLine("Indices");
2149 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
2150 for (int iter = 0; iter < indices.Length; iter++)
2151 {
2152 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
2153 }
2154 sw.WriteLine("VerticesFloats");
2155 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
2156 for (int iter = 0; iter < vertices.Length; iter++)
2157 {
2158 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
2159 }
2160
2161 // for (int i = 0; i < pVerticesCount; i++)
2162 // {
2163 //
2164 // string s = vertices[indices[i * 3]].ToString("0.0000");
2165 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
2166 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
2167 //
2168 // sw.Write(s + "\n");
2169 //}
2170
2171 sw.Close();
2172 }
2173
2174 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
2175 float scaleFactor, float collisionMargin)
2176 {
2177 const int upAxis = 2;
2178 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
2179 heightMap, scaleFactor,
2180 minHeight, maxHeight, upAxis,
2181 false);
2182 terrainShape.SetMargin(collisionMargin);
2183 terrainShape.SetUseDiamondSubdivision(true);
2184 terrainShape.SetUserPointer(id);
2185 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
2186 }
2187
2188 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
2189 {
2190 TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain;
2191 bool onOff = ponOff != 0;
2192 bool ret = false;
2193
2194 switch (tconstrain.GetConstraintType())
2195 {
2196 case TypedConstraintType.D6_CONSTRAINT_TYPE:
2197 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
2198 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
2199 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
2200 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
2201 ret = true;
2202 break;
2203 }
2204
2205
2206 return ret;
2207
2208 }
2209
2210 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
2211 out int updatedEntityCount, out int collidersCount)
2212 {
2213 /* TODO */
2214 updatedEntityCount = 0;
2215 collidersCount = 0;
2216
2217
2218 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
2219
2220 return ret;
2221 }
2222
2223 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
2224 out int updatedEntityCount, out EntityProperties[] updatedEntities,
2225 out int collidersCount, out CollisionDesc[] colliders)
2226 {
2227 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
2228 out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame);
2229 return epic;
2230 }
2231
2232 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
2233 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
2234 {
2235 int numSimSteps = 0;
2236 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
2237 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
2238 LastEntityProperty=0;
2239
2240
2241
2242
2243
2244
2245 LastCollisionDesc=0;
2246
2247 updatedEntityCount = 0;
2248 collidersCount = 0;
2249
2250
2251 if (pWorld is BulletWorldXNA)
2252 {
2253 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2254
2255 world.LastCollisionDesc = 0;
2256 world.LastEntityProperty = 0;
2257 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
2258
2259 PersistentManifold contactManifold;
2260 CollisionObject objA;
2261 CollisionObject objB;
2262 ManifoldPoint manifoldPoint;
2263 PairCachingGhostObject pairCachingGhostObject;
2264
2265 m_collisionsThisFrame = 0;
2266 int numManifolds = world.GetDispatcher().GetNumManifolds();
2267 for (int j = 0; j < numManifolds; j++)
2268 {
2269 contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
2270 int numContacts = contactManifold.GetNumContacts();
2271 if (numContacts == 0)
2272 continue;
2273
2274 objA = contactManifold.GetBody0() as CollisionObject;
2275 objB = contactManifold.GetBody1() as CollisionObject;
2276
2277 manifoldPoint = contactManifold.GetContactPoint(0);
2278 //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
2279 // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
2280
2281 RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance());
2282 m_collisionsThisFrame ++;
2283 if (m_collisionsThisFrame >= 9999999)
2284 break;
2285
2286
2287 }
2288
2289 foreach (GhostObject ghostObject in specialCollisionObjects.Values)
2290 {
2291 pairCachingGhostObject = ghostObject as PairCachingGhostObject;
2292 if (pairCachingGhostObject != null)
2293 {
2294 RecordGhostCollisions(pairCachingGhostObject);
2295 }
2296
2297 }
2298
2299
2300 updatedEntityCount = LastEntityProperty;
2301 updatedEntities = UpdatedObjects;
2302
2303 collidersCount = LastCollisionDesc;
2304 colliders = UpdatedCollisions;
2305
2306
2307 }
2308 else
2309 {
2310 //if (updatedEntities is null)
2311 //updatedEntities = new List<BulletXNA.EntityProperties>();
2312 //updatedEntityCount = 0;
2313
2314
2315 //collidersCount = 0;
2316
2317 updatedEntities = new EntityProperties[0];
2318
2319
2320 colliders = new CollisionDesc[0];
2321
2322 }
2323 return numSimSteps;
2324 }
2325 public void RecordGhostCollisions(PairCachingGhostObject obj)
2326 {
2327 IOverlappingPairCache cache = obj.GetOverlappingPairCache();
2328 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray();
2329
2330 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
2331 PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
2332 BroadphasePair collisionPair;
2333 PersistentManifold contactManifold;
2334
2335 CollisionObject objA;
2336 CollisionObject objB;
2337
2338 ManifoldPoint pt;
2339
2340 int numPairs = pairs.Count;
2341
2342 for (int i = 0; i < numPairs; i++)
2343 {
2344 manifoldArray.Clear();
2345 if (LastCollisionDesc < UpdatedCollisions.Length)
2346 break;
2347 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
2348 if (collisionPair == null)
2349 continue;
2350
2351 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
2352 for (int j = 0; j < manifoldArray.Count; j++)
2353 {
2354 contactManifold = manifoldArray[j];
2355 int numContacts = contactManifold.GetNumContacts();
2356 objA = contactManifold.GetBody0() as CollisionObject;
2357 objB = contactManifold.GetBody1() as CollisionObject;
2358 for (int p = 0; p < numContacts; p++)
2359 {
2360 pt = contactManifold.GetContactPoint(p);
2361 if (pt.GetDistance() < 0.0f)
2362 {
2363 RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance());
2364 break;
2365 }
2366 }
2367 }
2368 }
2369
2370 }
2371 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
2372 {
2373
2374 IndexedVector3 contactNormal = norm;
2375 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
2376 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
2377 {
2378 return;
2379 }
2380 uint idA = (uint)objA.GetUserPointer();
2381 uint idB = (uint)objB.GetUserPointer();
2382 if (idA > idB)
2383 {
2384 uint temp = idA;
2385 idA = idB;
2386 idB = temp;
2387 contactNormal = -contactNormal;
2388 }
2389
2390 //ulong collisionID = ((ulong) idA << 32) | idB;
2391
2392 CollisionDesc cDesc = new CollisionDesc()
2393 {
2394 aID = idA,
2395 bID = idB,
2396 point = new Vector3(contact.X,contact.Y,contact.Z),
2397 normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z),
2398 penetration = penetration
2399
2400 };
2401 if (world.LastCollisionDesc < world.UpdatedCollisions.Length)
2402 world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc);
2403 m_collisionsThisFrame++;
2404
2405
2406 }
2407 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject)
2408 {
2409 EntityProperties ent = new EntityProperties();
2410 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2411 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
2412 IndexedMatrix transform = collisionObject.GetWorldTransform();
2413 IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity();
2414 IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity();
2415 IndexedQuaternion rotation = transform.GetRotation();
2416 ent.Acceleration = Vector3.Zero;
2417 ent.ID = (uint)collisionObject.GetUserPointer();
2418 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
2419 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
2420 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
2421 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
2422 return ent;
2423 }
2424
2425 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */
2426 return false; }
2427
2428 public override Vector3 GetLocalScaling(BulletShape pShape)
2429 {
2430 CollisionShape shape = (pShape as BulletShapeXNA).shape;
2431 IndexedVector3 scale = shape.GetLocalScaling();
2432 return new Vector3(scale.X,scale.Y,scale.Z);
2433 }
2434
2435 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
2436 {
2437 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2438 if (world != null)
2439 {
2440 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
2441 {
2442 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
2443
2444 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
2445 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
2446 using (
2447 ClosestNotMeRayResultCallback rayCallback =
2448 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
2449 )
2450 {
2451 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
2452 if (rayCallback.HasHit())
2453 {
2454 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
2455 }
2456 return rayCallback.HasHit();
2457 }
2458 }
2459 }
2460 return false;
2461 }
2462}
2463
2464
2465
2466
2467 public class SimMotionState : DefaultMotionState
2468 {
2469 public RigidBody Rigidbody;
2470 public Vector3 ZeroVect;
2471
2472 private IndexedMatrix m_xform;
2473
2474 private EntityProperties m_properties;
2475 private EntityProperties m_lastProperties;
2476 private BSAPIXNA m_world;
2477
2478 const float POSITION_TOLERANCE = 0.05f;
2479 const float VELOCITY_TOLERANCE = 0.001f;
2480 const float ROTATION_TOLERANCE = 0.01f;
2481 const float ANGULARVELOCITY_TOLERANCE = 0.01f;
2482
2483 public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates)
2484 {
2485 IndexedQuaternion OrientationQuaterion = starTransform.GetRotation();
2486 m_properties = new EntityProperties()
2487 {
2488 ID = id,
2489 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z),
2490 Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W)
2491 };
2492 m_lastProperties = new EntityProperties()
2493 {
2494 ID = id,
2495 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z),
2496 Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W)
2497 };
2498 m_world = pWorld;
2499 m_xform = starTransform;
2500 }
2501
2502 public override void GetWorldTransform(out IndexedMatrix worldTrans)
2503 {
2504 worldTrans = m_xform;
2505 }
2506
2507 public override void SetWorldTransform(IndexedMatrix worldTrans)
2508 {
2509 SetWorldTransform(ref worldTrans);
2510 }
2511
2512 public override void SetWorldTransform(ref IndexedMatrix worldTrans)
2513 {
2514 SetWorldTransform(ref worldTrans, false);
2515 }
2516 public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force)
2517 {
2518 m_xform = worldTrans;
2519 // Put the new transform into m_properties
2520 IndexedQuaternion OrientationQuaternion = m_xform.GetRotation();
2521 IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity();
2522 IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity();
2523 m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z);
2524 m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y,
2525 OrientationQuaternion.Z, OrientationQuaternion.W);
2526 // A problem with stock Bullet is that we don't get an event when an object is deactivated.
2527 // This means that the last non-zero values for linear and angular velocity
2528 // are left in the viewer who does dead reconning and the objects look like
2529 // they float off.
2530 // BulletSim ships with a patch to Bullet which creates such an event.
2531 m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z);
2532 m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z);
2533
2534 if (force
2535
2536 || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE)
2537 || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE)
2538 // If the Velocity and AngularVelocity are zero, most likely the object has
2539 // been deactivated. If they both are zero and they have become zero recently,
2540 // make sure a property update is sent so the zeros make it to the viewer.
2541 || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect)
2542 &&
2543 (m_properties.Velocity != m_lastProperties.Velocity ||
2544 m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity))
2545 // If Velocity and AngularVelocity are non-zero but have changed, send an update.
2546 || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE)
2547 ||
2548 !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity,
2549 ANGULARVELOCITY_TOLERANCE)
2550 )
2551
2552
2553 {
2554 // Add this update to the list of updates for this frame.
2555 m_lastProperties = m_properties;
2556 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
2557 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
2558
2559 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
2560 }
2561
2562
2563
2564
2565 }
2566 public override void SetRigidBody(RigidBody body)
2567 {
2568 Rigidbody = body;
2569 }
2570 internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon)
2571 {
2572 return
2573 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2574 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2575 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon)));
2576 }
2577
2578 internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon)
2579 {
2580 return
2581 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2582 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2583 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
2584 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
2585 }
2586
2587 }
2588}
2589
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
new file mode 100755
index 0000000..bde4557
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
@@ -0,0 +1,457 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35
36using OMV = OpenMetaverse;
37
38namespace OpenSim.Region.Physics.BulletSPlugin
39{
40public class BSActorAvatarMove : BSActor
41{
42 BSVMotor m_velocityMotor;
43
44 // Set to true if we think we're going up stairs.
45 // This state is remembered because collisions will turn on and off as we go up stairs.
46 int m_walkingUpStairs;
47 // The amount the step up is applying. Used to smooth stair walking.
48 float m_lastStepUp;
49
50 // Jumping happens over several frames. If use applies up force while colliding, start the
51 // jump and allow the jump to continue for this number of frames.
52 int m_jumpFrames = 0;
53 float m_jumpVelocity = 0f;
54
55 public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
56 : base(physicsScene, pObj, actorName)
57 {
58 m_velocityMotor = null;
59 m_walkingUpStairs = 0;
60 m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
61 }
62
63 // BSActor.isActive
64 public override bool isActive
65 {
66 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
67 }
68
69 // Release any connections and resources used by the actor.
70 // BSActor.Dispose()
71 public override void Dispose()
72 {
73 base.SetEnabled(false);
74 DeactivateAvatarMove();
75 }
76
77 // Called when physical parameters (properties set in Bullet) need to be re-applied.
78 // Called at taint-time.
79 // BSActor.Refresh()
80 public override void Refresh()
81 {
82 m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
83
84 // If the object is physically active, add the hoverer prestep action
85 if (isActive)
86 {
87 ActivateAvatarMove();
88 }
89 else
90 {
91 DeactivateAvatarMove();
92 }
93 }
94
95 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
96 // Register a prestep action to restore physical requirements before the next simulation step.
97 // Called at taint-time.
98 // BSActor.RemoveDependencies()
99 public override void RemoveDependencies()
100 {
101 // Nothing to do for the hoverer since it is all software at pre-step action time.
102 }
103
104 // Usually called when target velocity changes to set the current velocity and the target
105 // into the movement motor.
106 public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
107 {
108 m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate()
109 {
110 if (m_velocityMotor != null)
111 {
112// if (targ == OMV.Vector3.Zero)
113// Util.PrintCallStack();
114//
115// Console.WriteLine("SetVelocityAndTarget, {0} {1}", vel, targ);
116 m_velocityMotor.Reset();
117 m_velocityMotor.SetTarget(targ);
118 m_velocityMotor.SetCurrent(vel);
119 m_velocityMotor.Enabled = true;
120 }
121 });
122 }
123
124 // If a hover motor has not been created, create one and start the hovering.
125 private void ActivateAvatarMove()
126 {
127 if (m_velocityMotor == null)
128 {
129 // Infinite decay and timescale values so motor only changes current to target values.
130 m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
131 0.2f, // time scale
132 BSMotor.Infinite, // decay time scale
133 1f // efficiency
134 );
135 m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold;
136 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
137 SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
138
139 m_physicsScene.BeforeStep += Mover;
140 m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty;
141
142 m_walkingUpStairs = 0;
143 }
144 }
145
146 private void DeactivateAvatarMove()
147 {
148 if (m_velocityMotor != null)
149 {
150 m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty;
151 m_physicsScene.BeforeStep -= Mover;
152 m_velocityMotor = null;
153 }
154 }
155
156 // Called just before the simulation step. Update the vertical position for hoverness.
157 private void Mover(float timeStep)
158 {
159 // Don't do movement while the object is selected.
160 if (!isActive)
161 return;
162
163 // TODO: Decide if the step parameters should be changed depending on the avatar's
164 // state (flying, colliding, ...). There is code in ODE to do this.
165
166 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
167 // specified for the avatar is the one that should be used. For falling, if the avatar
168 // is not flying and is not colliding then it is presumed to be falling and the Z
169 // component is not fooled with (thus allowing gravity to do its thing).
170 // When the avatar is standing, though, the user has specified a velocity of zero and
171 // the avatar should be standing. But if the avatar is pushed by something in the world
172 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
173 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
174 // errors can creap in and the avatar will slowly float off in some direction.
175 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
176 // from real pushing.
177 // The code below uses whether the collider is static or moving to decide whether to zero motion.
178
179 m_velocityMotor.Step(timeStep);
180 m_controllingPrim.IsStationary = false;
181
182 // If we're not supposed to be moving, make sure things are zero.
183 if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
184 {
185 // The avatar shouldn't be moving
186 m_velocityMotor.Zero();
187
188 if (m_controllingPrim.IsColliding)
189 {
190 // If we are colliding with a stationary object, presume we're standing and don't move around
191 if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect)
192 {
193 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
194 m_controllingPrim.IsStationary = true;
195 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
196 }
197
198 // Standing has more friction on the ground
199 if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
200 {
201 m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
202 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
203 }
204 }
205 else
206 {
207 if (m_controllingPrim.Flying)
208 {
209 // Flying and not colliding and velocity nearly zero.
210 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
211 }
212 else
213 {
214 //We are falling but are not touching any keys make sure not falling too fast
215 if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity)
216 {
217
218 OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass;
219 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce);
220 }
221
222 }
223 }
224
225 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
226 m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
227 }
228 else
229 {
230 // Supposed to be moving.
231 OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
232
233 if (m_controllingPrim.Friction != BSParam.AvatarFriction)
234 {
235 // Probably starting to walk. Set friction to moving friction.
236 m_controllingPrim.Friction = BSParam.AvatarFriction;
237 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
238 }
239
240 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
241 {
242 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
243 }
244
245 // Colliding and not flying with an upward force. The avatar must be trying to jump.
246 if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0)
247 {
248 // We allow the upward force to happen for this many frames.
249 m_jumpFrames = BSParam.AvatarJumpFrames;
250 m_jumpVelocity = stepVelocity.Z;
251 }
252
253 // The case where the avatar is not colliding and is not flying is special.
254 // The avatar is either falling or jumping and the user can be applying force to the avatar
255 // (force in some direction or force up or down).
256 // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity.
257 // If the user is trying to apply upward force but we're not colliding, assume the avatar
258 // is trying to jump and don't apply the upward force if not touching the ground any more.
259 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
260 {
261 // If upward velocity is being applied, this must be a jump and only allow that to go on so long
262 if (m_jumpFrames > 0)
263 {
264 // Since not touching the ground, only apply upward force for so long.
265 m_jumpFrames--;
266 stepVelocity.Z = m_jumpVelocity;
267 }
268 else
269 {
270
271 // Since we're not affected by anything, the avatar must be falling and we do not want that to be too fast.
272 if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity)
273 {
274
275 stepVelocity.Z = BSParam.AvatarTerminalVelocity;
276 }
277 else
278 {
279 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
280 }
281 }
282 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
283 }
284
285 //Alicia: Maintain minimum height when flying.
286 // SL has a flying effect that keeps the avatar flying above the ground by some margin
287 if (m_controllingPrim.Flying)
288 {
289 float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition)
290 + BSParam.AvatarFlyingGroundMargin;
291
292 if( m_controllingPrim.Position.Z < hover_height)
293 {
294 stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce;
295 }
296 }
297
298 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
299 OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
300
301 // Add special movement force to allow avatars to walk up stepped surfaces.
302 moveForce += WalkUpStairs();
303
304 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
305 m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
306 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
307 }
308 }
309
310 // Called just as the property update is received from the physics engine.
311 // Do any mode necessary for avatar movement.
312 private void Process_OnPreUpdateProperty(ref EntityProperties entprop)
313 {
314 // Don't change position if standing on a stationary object.
315 if (m_controllingPrim.IsStationary)
316 {
317 entprop.Position = m_controllingPrim.RawPosition;
318 entprop.Velocity = OMV.Vector3.Zero;
319 m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation);
320 }
321
322 }
323
324 // Decide if the character is colliding with a low object and compute a force to pop the
325 // avatar up so it can walk up and over the low objects.
326 private OMV.Vector3 WalkUpStairs()
327 {
328 OMV.Vector3 ret = OMV.Vector3.Zero;
329
330 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
331 m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying,
332 m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z);
333
334 // Check for stairs climbing if colliding, not flying and moving forward
335 if ( m_controllingPrim.IsColliding
336 && !m_controllingPrim.Flying
337 && m_controllingPrim.TargetVelocitySpeed > 0.1f )
338 {
339 // The range near the character's feet where we will consider stairs
340 // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
341 // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off
342 // from the height. Revisit size and this computation when height is scaled properly.
343 float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge;
344 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
345
346 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is.
347 // Find the highest 'good' collision.
348 OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
349 foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
350 {
351 // Don't care about collisions with the terrain
352 if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
353 {
354 BSPhysObject collisionObject;
355 if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject))
356 {
357 if (!collisionObject.IsVolumeDetect)
358 {
359 OMV.Vector3 touchPosition = kvp.Value.Position;
360 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
361 m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
362 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
363 {
364 // This contact is within the 'near the feet' range.
365 // The step is presumed to be more or less vertical. Thus the Z component should
366 // be nearly horizontal.
367 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
368 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
369 const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles
370 // m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}",
371 // m_controllingPrim.LocalID, directionFacing, touchNormal,
372 // Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) );
373 if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle
374 && (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle)
375 {
376 // The normal should be our contact point to the object so it is pointing away
377 // thus the difference between our facing orientation and the normal should be small.
378 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
379 if (diff < BSParam.AvatarStepApproachFactor)
380 {
381 if (highestTouchPosition.Z < touchPosition.Z)
382 highestTouchPosition = touchPosition;
383 }
384 }
385 }
386 }
387 }
388 }
389 }
390 m_walkingUpStairs = 0;
391 // If there is a good step sensing, move the avatar over the step.
392 if (highestTouchPosition != OMV.Vector3.Zero)
393 {
394 // Remember that we are going up stairs. This is needed because collisions
395 // will stop when we move up so this smoothes out that effect.
396 m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
397
398 m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
399 ret = ComputeStairCorrection(m_lastStepUp);
400 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
401 m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
402 }
403 }
404 else
405 {
406 // If we used to be going up stairs but are not now, smooth the case where collision goes away while
407 // we are bouncing up the stairs.
408 if (m_walkingUpStairs > 0)
409 {
410 m_walkingUpStairs--;
411 ret = ComputeStairCorrection(m_lastStepUp);
412 }
413 }
414
415 return ret;
416 }
417
418 private OMV.Vector3 ComputeStairCorrection(float stepUp)
419 {
420 OMV.Vector3 ret = OMV.Vector3.Zero;
421 OMV.Vector3 displacement = OMV.Vector3.Zero;
422
423 if (stepUp > 0f)
424 {
425 // Found the stairs contact point. Push up a little to raise the character.
426 if (BSParam.AvatarStepForceFactor > 0f)
427 {
428 float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
429 ret = new OMV.Vector3(0f, 0f, upForce);
430 }
431
432 // Also move the avatar up for the new height
433 if (BSParam.AvatarStepUpCorrectionFactor > 0f)
434 {
435 // Move the avatar up related to the height of the collision
436 displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor);
437 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
438 }
439 else
440 {
441 if (BSParam.AvatarStepUpCorrectionFactor < 0f)
442 {
443 // Move the avatar up about the specified step height
444 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight);
445 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
446 }
447 }
448 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,stepUp={1},isp={2},force={3}",
449 m_controllingPrim.LocalID, stepUp, displacement, ret);
450
451 }
452 return ret;
453 }
454}
455}
456
457
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
new file mode 100755
index 0000000..e54c27b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
@@ -0,0 +1,174 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorHover : BSActor
40{
41 private BSFMotor m_hoverMotor;
42
43 public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_hoverMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 DeactivateHover();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
70
71 // If not active any more, turn me off
72 if (!m_controllingPrim.HoverActive)
73 {
74 SetEnabled(false);
75 }
76
77 // If the object is physically active, add the hoverer prestep action
78 if (isActive)
79 {
80 ActivateHover();
81 }
82 else
83 {
84 DeactivateHover();
85 }
86 }
87
88 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
89 // Register a prestep action to restore physical requirements before the next simulation step.
90 // Called at taint-time.
91 // BSActor.RemoveDependencies()
92 public override void RemoveDependencies()
93 {
94 // Nothing to do for the hoverer since it is all software at pre-step action time.
95 }
96
97 // If a hover motor has not been created, create one and start the hovering.
98 private void ActivateHover()
99 {
100 if (m_hoverMotor == null)
101 {
102 // Turning the target on
103 m_hoverMotor = new BSFMotor("BSActorHover",
104 m_controllingPrim.HoverTau, // timeScale
105 BSMotor.Infinite, // decay time scale
106 1f // efficiency
107 );
108 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
109 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
110 m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
111
112 m_physicsScene.BeforeStep += Hoverer;
113 }
114 }
115
116 private void DeactivateHover()
117 {
118 if (m_hoverMotor != null)
119 {
120 m_physicsScene.BeforeStep -= Hoverer;
121 m_hoverMotor = null;
122 }
123 }
124
125 // Called just before the simulation step. Update the vertical position for hoverness.
126 private void Hoverer(float timeStep)
127 {
128 // Don't do hovering while the object is selected.
129 if (!isActive)
130 return;
131
132 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
133 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
134 float targetHeight = m_hoverMotor.Step(timeStep);
135
136 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
137 // Compute the amount of force to push us there.
138 float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
139 // Undo anything the object thinks it's doing at the moment
140 moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
141
142 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
143 m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
144 m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
145 }
146
147 // Based on current position, determine what we should be hovering at now.
148 // Must recompute often. What if we walked offa cliff>
149 private float ComputeCurrentHoverHeight()
150 {
151 float ret = m_controllingPrim.HoverHeight;
152 float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
153
154 switch (m_controllingPrim.HoverType)
155 {
156 case PIDHoverType.Ground:
157 ret = groundHeight + m_controllingPrim.HoverHeight;
158 break;
159 case PIDHoverType.GroundAndWater:
160 float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
161 if (groundHeight > waterHeight)
162 {
163 ret = groundHeight + m_controllingPrim.HoverHeight;
164 }
165 else
166 {
167 ret = waterHeight + m_controllingPrim.HoverHeight;
168 }
169 break;
170 }
171 return ret;
172 }
173}
174}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
new file mode 100755
index 0000000..3b3c161
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
@@ -0,0 +1,219 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public class BSActorLockAxis : BSActor
38{
39 private BSConstraint LockAxisConstraint = null;
40 private bool HaveRegisteredForBeforeStepCallback = false;
41
42 // The lock access flags (which axises were locked) when the contraint was built.
43 // Used to see if locking has changed since when the constraint was built.
44 OMV.Vector3 LockAxisLinearFlags;
45 OMV.Vector3 LockAxisAngularFlags;
46
47 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
48 : base(physicsScene, pObj, actorName)
49 {
50 m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
51 LockAxisConstraint = null;
52 HaveRegisteredForBeforeStepCallback = false;
53 }
54
55 // BSActor.isActive
56 public override bool isActive
57 {
58 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
59 }
60
61 // Release any connections and resources used by the actor.
62 // BSActor.Dispose()
63 public override void Dispose()
64 {
65 Enabled = false;
66 UnRegisterForBeforeStepCallback();
67 RemoveAxisLockConstraint();
68 }
69
70 // Called when physical parameters (properties set in Bullet) need to be re-applied.
71 // Called at taint-time.
72 // BSActor.Refresh()
73 public override void Refresh()
74 {
75 // Since the axis logging is done with a constraint, Refresh() time is good for
76 // changing parameters but this needs to wait until the prim/linkset is physically
77 // constructed. Therefore, the constraint itself is placed at pre-step time.
78
79 // If all the axis are free, we don't need to exist
80 // Refresh() only turns off. Enabling is done by InitializeAxisActor()
81 // whenever parameters are changed.
82 // This leaves 'enable' free to turn off an actor when it is not wanted to run.
83 if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree
84 && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree)
85 {
86 Enabled = false;
87 }
88
89 if (isActive)
90 {
91 RegisterForBeforeStepCallback();
92 }
93 else
94 {
95 RemoveDependencies();
96 UnRegisterForBeforeStepCallback();
97 }
98 }
99
100 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
101 // Register a prestep action to restore physical requirements before the next simulation step.
102 // Called at taint-time.
103 // BSActor.RemoveDependencies()
104 public override void RemoveDependencies()
105 {
106 RemoveAxisLockConstraint();
107 }
108
109 private void RegisterForBeforeStepCallback()
110 {
111 if (!HaveRegisteredForBeforeStepCallback)
112 {
113 m_physicsScene.BeforeStep += PhysicsScene_BeforeStep;
114 HaveRegisteredForBeforeStepCallback = true;
115 }
116 }
117
118 private void UnRegisterForBeforeStepCallback()
119 {
120 if (HaveRegisteredForBeforeStepCallback)
121 {
122 m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep;
123 HaveRegisteredForBeforeStepCallback = false;
124 }
125 }
126
127 private void PhysicsScene_BeforeStep(float timestep)
128 {
129 // If all the axis are free, we don't need to exist
130 if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree
131 && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree)
132 {
133 Enabled = false;
134 }
135
136 // If the object is physically active, add the axis locking constraint
137 if (isActive)
138 {
139 // Check to see if the locking parameters have changed
140 if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags
141 || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags)
142 {
143 // The locking has changed. Remove the old constraint and build a new one
144 RemoveAxisLockConstraint();
145 }
146
147 AddAxisLockConstraint();
148 }
149 else
150 {
151 RemoveAxisLockConstraint();
152 }
153 }
154
155 // Note that this relies on being called at TaintTime
156 private void AddAxisLockConstraint()
157 {
158 if (LockAxisConstraint == null)
159 {
160 // Lock that axis by creating a 6DOF constraint that has one end in the world and
161 // the other in the object.
162 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
163 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
164
165 // Remove any existing axis constraint (just to be sure)
166 RemoveAxisLockConstraint();
167
168 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
169 OMV.Vector3.Zero, OMV.Quaternion.Identity,
170 false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
171 LockAxisConstraint = axisConstrainer;
172 m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
173
174 // Remember the clocking being inforced so we can notice if they have changed
175 LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis;
176 LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis;
177
178 // The constraint is tied to the world and oriented to the prim.
179
180 if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh))
181 {
182 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits",
183 m_controllingPrim.LocalID);
184 }
185
186 if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh))
187 {
188 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits",
189 m_controllingPrim.LocalID);
190 }
191
192 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
193 m_controllingPrim.LocalID,
194 m_controllingPrim.LockedLinearAxisLow,
195 m_controllingPrim.LockedLinearAxisHigh,
196 m_controllingPrim.LockedAngularAxisLow,
197 m_controllingPrim.LockedAngularAxisHigh);
198
199 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
200 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
201
202 axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
203
204 RegisterForBeforeStepCallback();
205 }
206 }
207
208 private void RemoveAxisLockConstraint()
209 {
210 UnRegisterForBeforeStepCallback();
211 if (LockAxisConstraint != null)
212 {
213 m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
214 LockAxisConstraint = null;
215 m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID);
216 }
217 }
218}
219}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
new file mode 100755
index 0000000..1145006
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
@@ -0,0 +1,220 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorMoveToTarget : BSActor
40{
41 private BSVMotor m_targetMotor;
42
43 public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_targetMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 // MoveToTarget only works on physical prims
54 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
55 }
56
57 // Release any connections and resources used by the actor.
58 // BSActor.Dispose()
59 public override void Dispose()
60 {
61 Enabled = false;
62 DeactivateMoveToTarget();
63 }
64
65 // Called when physical parameters (properties set in Bullet) need to be re-applied.
66 // Called at taint-time.
67 // BSActor.Refresh()
68 public override void Refresh()
69 {
70 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}",
71 m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive,
72 m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau );
73
74 // If not active any more...
75 if (!m_controllingPrim.MoveToTargetActive)
76 {
77 Enabled = false;
78 }
79
80 if (isActive)
81 {
82 ActivateMoveToTarget();
83 }
84 else
85 {
86 DeactivateMoveToTarget();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the moveToTarget since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateMoveToTarget()
101 {
102 if (m_targetMotor == null)
103 {
104 // We're taking over after this.
105 m_controllingPrim.ZeroMotion(true);
106
107 /* Someday use the PID controller
108 m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString());
109 m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau;
110 m_targetMotor.Efficiency = 1f;
111 */
112 m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(),
113 m_controllingPrim.MoveToTargetTau, // timeScale
114 BSMotor.Infinite, // decay time scale
115 1f // efficiency
116 );
117 m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
118 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
119 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
120
121 // m_physicsScene.BeforeStep += Mover;
122 m_physicsScene.BeforeStep += Mover2;
123 }
124 else
125 {
126 // If already allocated, make sure the target and other paramters are current
127 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
128 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
129 }
130 }
131
132 private void DeactivateMoveToTarget()
133 {
134 if (m_targetMotor != null)
135 {
136 // m_physicsScene.BeforeStep -= Mover;
137 m_physicsScene.BeforeStep -= Mover2;
138 m_targetMotor = null;
139 }
140 }
141
142 // Origional mover that set the objects position to move to the target.
143 // The problem was that gravity would keep trying to push the object down so
144 // the overall downward velocity would increase to infinity.
145 // Called just before the simulation step.
146 private void Mover(float timeStep)
147 {
148 // Don't do hovering while the object is selected.
149 if (!isActive)
150 return;
151
152 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
153
154 // 'movePosition' is where we'd like the prim to be at this moment.
155 OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
156
157 // If we are very close to our target, turn off the movement motor.
158 if (m_targetMotor.ErrorIsZero())
159 {
160 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}",
161 m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
162 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
163 m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
164 // Setting the position does not cause the physics engine to generate a property update. Force it.
165 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
166 }
167 else
168 {
169 m_controllingPrim.ForcePosition = movePosition;
170 // Setting the position does not cause the physics engine to generate a property update. Force it.
171 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
172 }
173 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}",
174 m_controllingPrim.LocalID, origPosition, movePosition);
175 }
176
177 // Version of mover that applies forces to move the physical object to the target.
178 // Also overcomes gravity so the object doesn't just drop to the ground.
179 // Called just before the simulation step.
180 private void Mover2(float timeStep)
181 {
182 // Don't do hovering while the object is selected.
183 if (!isActive)
184 return;
185
186 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
187 OMV.Vector3 addedForce = OMV.Vector3.Zero;
188
189 // CorrectionVector is the movement vector required this step
190 OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition);
191
192 // If we are very close to our target, turn off the movement motor.
193 if (m_targetMotor.ErrorIsZero())
194 {
195 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}",
196 m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
197 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
198 m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
199 // Setting the position does not cause the physics engine to generate a property update. Force it.
200 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
201 }
202 else
203 {
204 // First force to move us there -- the motor return a timestep scaled value.
205 addedForce = correctionVector / timeStep;
206 // Remove the existing velocity (only the moveToTarget force counts)
207 addedForce -= m_controllingPrim.RawVelocity;
208 // Overcome gravity.
209 addedForce -= m_controllingPrim.Gravity;
210
211 // Add enough force to overcome the mass of the object
212 addedForce *= m_controllingPrim.Mass;
213
214 m_controllingPrim.AddForce(addedForce, false /* pushForce */, true /* inTaintTime */);
215 }
216 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}",
217 m_controllingPrim.LocalID, origPosition, addedForce);
218 }
219}
220}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs
new file mode 100755
index 0000000..4e81363
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs
@@ -0,0 +1,138 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorSetForce : BSActor
40{
41 BSFMotor m_forceMotor;
42
43 public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_forceMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 DeactivateSetForce();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
70
71 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
72 if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
73 {
74 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
75 Enabled = false;
76 return;
77 }
78
79 // If the object is physically active, add the hoverer prestep action
80 if (isActive)
81 {
82 ActivateSetForce();
83 }
84 else
85 {
86 DeactivateSetForce();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the hoverer since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateSetForce()
101 {
102 if (m_forceMotor == null)
103 {
104 // A fake motor that might be used someday
105 m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f);
106
107 m_physicsScene.BeforeStep += Mover;
108 }
109 }
110
111 private void DeactivateSetForce()
112 {
113 if (m_forceMotor != null)
114 {
115 m_physicsScene.BeforeStep -= Mover;
116 m_forceMotor = null;
117 }
118 }
119
120 // Called just before the simulation step. Update the vertical position for hoverness.
121 private void Mover(float timeStep)
122 {
123 // Don't do force while the object is selected.
124 if (!isActive)
125 return;
126
127 m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
128 if (m_controllingPrim.PhysBody.HasPhysicalBody)
129 {
130 m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
131 m_controllingPrim.ActivateIfPhysical(false);
132 }
133
134 // TODO:
135 }
136}
137}
138
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
new file mode 100755
index 0000000..79e1d38
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorSetTorque : BSActor
40{
41 BSFMotor m_torqueMotor;
42
43 public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_torqueMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 DeactivateSetTorque();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
70
71 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
72 if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
73 {
74 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
75 Enabled = false;
76 return;
77 }
78
79 // If the object is physically active, add the hoverer prestep action
80 if (isActive)
81 {
82 ActivateSetTorque();
83 }
84 else
85 {
86 DeactivateSetTorque();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the hoverer since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateSetTorque()
101 {
102 if (m_torqueMotor == null)
103 {
104 // A fake motor that might be used someday
105 m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f);
106
107 m_physicsScene.BeforeStep += Mover;
108 }
109 }
110
111 private void DeactivateSetTorque()
112 {
113 if (m_torqueMotor != null)
114 {
115 m_physicsScene.BeforeStep -= Mover;
116 m_torqueMotor = null;
117 }
118 }
119
120 // Called just before the simulation step. Update the vertical position for hoverness.
121 private void Mover(float timeStep)
122 {
123 // Don't do force while the object is selected.
124 if (!isActive)
125 return;
126
127 m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
128 if (m_controllingPrim.PhysBody.HasPhysicalBody)
129 {
130 m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
131 m_controllingPrim.ActivateIfPhysical(false);
132 }
133
134 // TODO:
135 }
136}
137}
138
139
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
new file mode 100755
index 0000000..7f45e2c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
@@ -0,0 +1,154 @@
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
31namespace OpenSim.Region.Physics.BulletSPlugin
32{
33public class BSActorCollection
34{
35 private Dictionary<string, BSActor> m_actors;
36
37 public BSActorCollection()
38 {
39 m_actors = new Dictionary<string, BSActor>();
40 }
41 public void Add(string name, BSActor actor)
42 {
43 lock (m_actors)
44 {
45 if (!m_actors.ContainsKey(name))
46 {
47 m_actors[name] = actor;
48 }
49 }
50 }
51 public bool RemoveAndRelease(string name)
52 {
53 bool ret = false;
54 lock (m_actors)
55 {
56 if (m_actors.ContainsKey(name))
57 {
58 BSActor beingRemoved = m_actors[name];
59 m_actors.Remove(name);
60 beingRemoved.Dispose();
61 ret = true;
62 }
63 }
64 return ret;
65 }
66 public void Clear()
67 {
68 lock (m_actors)
69 {
70 ForEachActor(a => a.Dispose());
71 m_actors.Clear();
72 }
73 }
74 public void Dispose()
75 {
76 Clear();
77 }
78 public bool HasActor(string name)
79 {
80 return m_actors.ContainsKey(name);
81 }
82 public bool TryGetActor(string actorName, out BSActor theActor)
83 {
84 return m_actors.TryGetValue(actorName, out theActor);
85 }
86 public void ForEachActor(Action<BSActor> act)
87 {
88 lock (m_actors)
89 {
90 foreach (KeyValuePair<string, BSActor> kvp in m_actors)
91 act(kvp.Value);
92 }
93 }
94
95 public void Enable(bool enabl)
96 {
97 ForEachActor(a => a.SetEnabled(enabl));
98 }
99 public void Refresh()
100 {
101 ForEachActor(a => a.Refresh());
102 }
103 public void RemoveDependencies()
104 {
105 ForEachActor(a => a.RemoveDependencies());
106 }
107}
108
109// =============================================================================
110/// <summary>
111/// Each physical object can have 'actors' who are pushing the object around.
112/// This can be used for hover, locking axis, making vehicles, etc.
113/// Each physical object can have multiple actors acting on it.
114///
115/// An actor usually registers itself with physics scene events (pre-step action)
116/// and modifies the parameters on the host physical object.
117/// </summary>
118public abstract class BSActor
119{
120 protected BSScene m_physicsScene { get; private set; }
121 protected BSPhysObject m_controllingPrim { get; private set; }
122 public virtual bool Enabled { get; set; }
123 public string ActorName { get; private set; }
124
125 public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
126 {
127 m_physicsScene = physicsScene;
128 m_controllingPrim = pObj;
129 ActorName = actorName;
130 Enabled = true;
131 }
132
133 // Return 'true' if activily updating the prim
134 public virtual bool isActive
135 {
136 get { return Enabled; }
137 }
138
139 // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
140 // Anyone else should assign true/false to 'Enabled'.
141 public void SetEnabled(bool setEnabled)
142 {
143 Enabled = setEnabled;
144 }
145 // Release any connections and resources used by the actor.
146 public abstract void Dispose();
147 // Called when physical parameters (properties set in Bullet) need to be re-applied.
148 public abstract void Refresh();
149 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
150 // Register a prestep action to restore physical requirements before the next simulation step.
151 public abstract void RemoveDependencies();
152
153}
154}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
new file mode 100644
index 0000000..8491c0f
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
@@ -0,0 +1,763 @@
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 GEAR_CONSTRAINT_TYPE, // added in Bullet 2.82
47 FIXED_CONSTRAINT_TYPE, // added in Bullet 2.82
48 MAX_CONSTRAINT_TYPE, // last type defined by Bullet
49 //
50 BS_FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving
51}
52
53// ===============================================================================
54[StructLayout(LayoutKind.Sequential)]
55public struct ConvexHull
56{
57 Vector3 Offset;
58 int VertexCount;
59 Vector3[] Vertices;
60}
61public enum BSPhysicsShapeType
62{
63 SHAPE_UNKNOWN = 0,
64 SHAPE_CAPSULE = 1,
65 SHAPE_BOX = 2,
66 SHAPE_CONE = 3,
67 SHAPE_CYLINDER = 4,
68 SHAPE_SPHERE = 5,
69 SHAPE_MESH = 6,
70 SHAPE_HULL = 7,
71 // following defined by BulletSim
72 SHAPE_GROUNDPLANE = 20,
73 SHAPE_TERRAIN = 21,
74 SHAPE_COMPOUND = 22,
75 SHAPE_HEIGHTMAP = 23,
76 SHAPE_AVATAR = 24,
77 SHAPE_CONVEXHULL= 25,
78 SHAPE_GIMPACT = 26,
79};
80
81// The native shapes have predefined shape hash keys
82public enum FixedShapeKey : ulong
83{
84 KEY_NONE = 0,
85 KEY_BOX = 1,
86 KEY_SPHERE = 2,
87 KEY_CONE = 3,
88 KEY_CYLINDER = 4,
89 KEY_CAPSULE = 5,
90 KEY_AVATAR = 6,
91}
92
93[StructLayout(LayoutKind.Sequential)]
94public struct ShapeData
95{
96 public UInt32 ID;
97 public BSPhysicsShapeType Type;
98 public Vector3 Position;
99 public Quaternion Rotation;
100 public Vector3 Velocity;
101 public Vector3 Scale;
102 public float Mass;
103 public float Buoyancy;
104 public System.UInt64 HullKey;
105 public System.UInt64 MeshKey;
106 public float Friction;
107 public float Restitution;
108 public float Collidable; // true of things bump into this
109 public float Static; // true if a static object. Otherwise gravity, etc.
110 public float Solid; // true if object cannot be passed through
111 public Vector3 Size;
112
113 // note that bools are passed as floats since bool size changes by language and architecture
114 public const float numericTrue = 1f;
115 public const float numericFalse = 0f;
116}
117[StructLayout(LayoutKind.Sequential)]
118public struct SweepHit
119{
120 public UInt32 ID;
121 public float Fraction;
122 public Vector3 Normal;
123 public Vector3 Point;
124}
125[StructLayout(LayoutKind.Sequential)]
126public struct RaycastHit
127{
128 public UInt32 ID;
129 public float Fraction;
130 public Vector3 Normal;
131}
132[StructLayout(LayoutKind.Sequential)]
133public struct CollisionDesc
134{
135 public UInt32 aID;
136 public UInt32 bID;
137 public Vector3 point;
138 public Vector3 normal;
139 public float penetration;
140}
141[StructLayout(LayoutKind.Sequential)]
142public struct EntityProperties
143{
144 public UInt32 ID;
145 public Vector3 Position;
146 public Quaternion Rotation;
147 public Vector3 Velocity;
148 public Vector3 Acceleration;
149 public Vector3 RotationalVelocity;
150
151 public override string ToString()
152 {
153 StringBuilder buff = new StringBuilder();
154 buff.Append("<i=");
155 buff.Append(ID.ToString());
156 buff.Append(",p=");
157 buff.Append(Position.ToString());
158 buff.Append(",r=");
159 buff.Append(Rotation.ToString());
160 buff.Append(",v=");
161 buff.Append(Velocity.ToString());
162 buff.Append(",a=");
163 buff.Append(Acceleration.ToString());
164 buff.Append(",rv=");
165 buff.Append(RotationalVelocity.ToString());
166 buff.Append(">");
167 return buff.ToString();
168 }
169}
170
171// Format of this structure must match the definition in the C++ code
172// NOTE: adding the X causes compile breaks if used. These are unused symbols
173// that can be removed from both here and the unmanaged definition of this structure.
174[StructLayout(LayoutKind.Sequential)]
175public struct ConfigurationParameters
176{
177 public float defaultFriction;
178 public float defaultDensity;
179 public float defaultRestitution;
180 public float collisionMargin;
181 public float gravity;
182
183 public float maxPersistantManifoldPoolSize;
184 public float maxCollisionAlgorithmPoolSize;
185 public float shouldDisableContactPoolDynamicAllocation;
186 public float shouldForceUpdateAllAabbs;
187 public float shouldRandomizeSolverOrder;
188 public float shouldSplitSimulationIslands;
189 public float shouldEnableFrictionCaching;
190 public float numberOfSolverIterations;
191 public float useSingleSidedMeshes;
192 public float globalContactBreakingThreshold;
193
194 public float physicsLoggingFrames;
195
196 public const float numericTrue = 1f;
197 public const float numericFalse = 0f;
198}
199
200// Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library.
201[StructLayout(LayoutKind.Sequential)]
202public struct HACDParams
203{
204 // usual default values
205 public float maxVerticesPerHull; // 100
206 public float minClusters; // 2
207 public float compacityWeight; // 0.1
208 public float volumeWeight; // 0.0
209 public float concavity; // 100
210 public float addExtraDistPoints; // false
211 public float addNeighboursDistPoints; // false
212 public float addFacesPoints; // false
213 public float shouldAdjustCollisionMargin; // false
214 // VHACD
215 public float whichHACD; // zero if Bullet HACD, non-zero says VHACD
216 // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html
217 public float vHACDresolution; // 100,000 max number of voxels generated during voxelization stage
218 public float vHACDdepth; // 20 max number of clipping stages
219 public float vHACDconcavity; // 0.0025 maximum concavity
220 public float vHACDplaneDownsampling; // 4 granularity of search for best clipping plane
221 public float vHACDconvexHullDownsampling; // 4 precision of hull gen process
222 public float vHACDalpha; // 0.05 bias toward clipping along symmetry planes
223 public float vHACDbeta; // 0.05 bias toward clipping along revolution axis
224 public float vHACDgamma; // 0.00125 max concavity when merging
225 public float vHACDpca; // 0 on/off normalizing mesh before decomp
226 public float vHACDmode; // 0 0:voxel based, 1: tetrahedron based
227 public float vHACDmaxNumVerticesPerCH; // 64 max triangles per convex hull
228 public float vHACDminVolumePerCH; // 0.0001 sampling of generated convex hulls
229}
230
231// The states a bullet collision object can have
232public enum ActivationState : uint
233{
234 ACTIVE_TAG = 1,
235 ISLAND_SLEEPING,
236 WANTS_DEACTIVATION,
237 DISABLE_DEACTIVATION,
238 DISABLE_SIMULATION,
239}
240
241public enum CollisionObjectTypes : int
242{
243 CO_COLLISION_OBJECT = 1 << 0,
244 CO_RIGID_BODY = 1 << 1,
245 CO_GHOST_OBJECT = 1 << 2,
246 CO_SOFT_BODY = 1 << 3,
247 CO_HF_FLUID = 1 << 4,
248 CO_USER_TYPE = 1 << 5,
249}
250
251// Values used by Bullet and BulletSim to control object properties.
252// Bullet's "CollisionFlags" has more to do with operations on the
253// object (if collisions happen, if gravity effects it, ...).
254public enum CollisionFlags : uint
255{
256 CF_STATIC_OBJECT = 1 << 0,
257 CF_KINEMATIC_OBJECT = 1 << 1,
258 CF_NO_CONTACT_RESPONSE = 1 << 2,
259 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
260 CF_CHARACTER_OBJECT = 1 << 4,
261 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
262 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
263 // Following used by BulletSim to control collisions and updates
264 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
265 BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
266 BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
267 BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
268 BS_NONE = 0,
269 BS_ALL = 0x7FFF // collision flags are a signed short
270};
271
272// Values f collisions groups and masks
273public enum CollisionFilterGroups : uint
274{
275 // Don't use the bit definitions!! Define the use in a
276 // filter/mask definition below. This way collision interactions
277 // are more easily found and debugged.
278 BNoneGroup = 0,
279 BDefaultGroup = 1 << 0, // 0001
280 BStaticGroup = 1 << 1, // 0002
281 BKinematicGroup = 1 << 2, // 0004
282 BDebrisGroup = 1 << 3, // 0008
283 BSensorTrigger = 1 << 4, // 0010
284 BCharacterGroup = 1 << 5, // 0020
285 BAllGroup = 0x0007FFF, // collision flags are a signed short
286 // Filter groups defined by BulletSim
287 BGroundPlaneGroup = 1 << 8, // 0400
288 BTerrainGroup = 1 << 9, // 0800
289 BRaycastGroup = 1 << 10, // 1000
290 BSolidGroup = 1 << 11, // 2000
291 // BLinksetGroup = xx // a linkset proper is either static or dynamic
292 BLinksetChildGroup = 1 << 12, // 4000
293};
294
295// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
296// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
297public enum ConstraintParams : int
298{
299 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
300 BT_CONSTRAINT_STOP_ERP,
301 BT_CONSTRAINT_CFM,
302 BT_CONSTRAINT_STOP_CFM,
303};
304public enum ConstraintParamAxis : int
305{
306 AXIS_LINEAR_X = 0,
307 AXIS_LINEAR_Y,
308 AXIS_LINEAR_Z,
309 AXIS_ANGULAR_X,
310 AXIS_ANGULAR_Y,
311 AXIS_ANGULAR_Z,
312 AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls
313 AXIS_ANGULAR_ALL,
314 AXIS_ALL
315};
316
317public abstract class BSAPITemplate
318{
319// Returns the name of the underlying Bullet engine
320public abstract string BulletEngineName { get; }
321public abstract string BulletEngineVersion { get; protected set;}
322
323// Initialization and simulation
324public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
325 int maxCollisions, ref CollisionDesc[] collisionArray,
326 int maxUpdates, ref EntityProperties[] updateArray
327 );
328
329public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
330 out int updatedEntityCount, out int collidersCount);
331
332public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
333
334public abstract void Shutdown(BulletWorld sim);
335
336public abstract bool PushUpdate(BulletBody obj);
337
338// =====================================================================================
339// Mesh, hull, shape and body creation helper routines
340public abstract BulletShape CreateMeshShape(BulletWorld world,
341 int indicesCount, int[] indices,
342 int verticesCount, float[] vertices );
343
344public abstract BulletShape CreateGImpactShape(BulletWorld world,
345 int indicesCount, int[] indices,
346 int verticesCount, float[] vertices );
347
348public abstract BulletShape CreateHullShape(BulletWorld world,
349 int hullCount, float[] hulls);
350
351public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms);
352
353public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
354
355public abstract BulletShape CreateConvexHullShape(BulletWorld world,
356 int indicesCount, int[] indices,
357 int verticesCount, float[] vertices );
358
359public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
360
361public abstract bool IsNativeShape(BulletShape shape);
362
363public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
364
365public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
366
367public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
368
369public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
370
371public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
372
373public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
374
375public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
376
377public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
378
379public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
380
381public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
382
383public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
384
385public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
386
387public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
388
389public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
390
391public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
392
393public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
394
395public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
396
397// =====================================================================================
398public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
399
400public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
401 float scaleFactor, float collisionMargin);
402
403// =====================================================================================
404// Constraint creation and helper routines
405public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
406 Vector3 frame1loc, Quaternion frame1rot,
407 Vector3 frame2loc, Quaternion frame2rot,
408 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
409
410public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
411 Vector3 joinPoint,
412 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
413
414public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
415 Vector3 frameInBloc, Quaternion frameInBrot,
416 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
417
418public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
419 Vector3 frame1loc, Quaternion frame1rot,
420 Vector3 frame2loc, Quaternion frame2rot,
421 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
422
423public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
424 Vector3 pivotinA, Vector3 pivotinB,
425 Vector3 axisInA, Vector3 axisInB,
426 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
427
428public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
429 Vector3 frameInAloc, Quaternion frameInArot,
430 Vector3 frameInBloc, Quaternion frameInBrot,
431 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
432
433public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
434 Vector3 frameInAloc, Quaternion frameInArot,
435 Vector3 frameInBloc, Quaternion frameInBrot,
436 bool disableCollisionsBetweenLinkedBodies);
437
438public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
439 Vector3 axisInA, Vector3 axisInB,
440 float ratio, bool disableCollisionsBetweenLinkedBodies);
441
442public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
443 Vector3 pivotInA, Vector3 pivotInB,
444 bool disableCollisionsBetweenLinkedBodies);
445
446public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
447
448public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
449
450public abstract bool SetFrames(BulletConstraint constrain,
451 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
452
453public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
454
455public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
456
457public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
458
459public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
460
461public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
462
463public const int HINGE_NOT_SPECIFIED = -1;
464public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation);
465
466public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse);
467
468public const int SPRING_NOT_SPECIFIED = -1;
469public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint);
470
471public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss);
472
473public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping);
474
475public const int SLIDER_LOWER_LIMIT = 0;
476public const int SLIDER_UPPER_LIMIT = 1;
477public const int SLIDER_LINEAR = 2;
478public const int SLIDER_ANGULAR = 3;
479public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val);
480
481public const int SLIDER_SET_SOFTNESS = 4;
482public const int SLIDER_SET_RESTITUTION = 5;
483public const int SLIDER_SET_DAMPING = 6;
484public const int SLIDER_SET_DIRECTION = 7;
485public const int SLIDER_SET_LIMIT = 8;
486public const int SLIDER_SET_ORTHO = 9;
487public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
488
489public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse);
490
491public const int SLIDER_MOTOR_VELOCITY = 10;
492public const int SLIDER_MAX_MOTOR_FORCE = 11;
493public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val);
494
495public abstract bool CalculateTransforms(BulletConstraint constrain);
496
497public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
498
499public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
500
501// =====================================================================================
502// btCollisionWorld entries
503public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
504
505public abstract void UpdateAabbs(BulletWorld world);
506
507public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
508
509public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
510
511// =====================================================================================
512// btDynamicsWorld entries
513// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
514public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
515
516public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
517
518public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj);
519
520public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
521
522public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
523// =====================================================================================
524// btCollisionObject entries
525public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
526
527public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
528
529public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
530
531public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
532
533public abstract float GetContactProcessingThreshold(BulletBody obj);
534
535public abstract bool IsStaticObject(BulletBody obj);
536
537public abstract bool IsKinematicObject(BulletBody obj);
538
539public abstract bool IsStaticOrKinematicObject(BulletBody obj);
540
541public abstract bool HasContactResponse(BulletBody obj);
542
543public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
544
545public abstract BulletShape GetCollisionShape(BulletBody obj);
546
547public abstract int GetActivationState(BulletBody obj);
548
549public abstract void SetActivationState(BulletBody obj, int state);
550
551public abstract void SetDeactivationTime(BulletBody obj, float dtime);
552
553public abstract float GetDeactivationTime(BulletBody obj);
554
555public abstract void ForceActivationState(BulletBody obj, ActivationState state);
556
557public abstract void Activate(BulletBody obj, bool forceActivation);
558
559public abstract bool IsActive(BulletBody obj);
560
561public abstract void SetRestitution(BulletBody obj, float val);
562
563public abstract float GetRestitution(BulletBody obj);
564
565public abstract void SetFriction(BulletBody obj, float val);
566
567public abstract float GetFriction(BulletBody obj);
568
569public abstract Vector3 GetPosition(BulletBody obj);
570
571public abstract Quaternion GetOrientation(BulletBody obj);
572
573public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
574
575// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
576
577// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
578
579public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
580
581public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
582
583public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
584
585public abstract float GetHitFraction(BulletBody obj);
586
587public abstract void SetHitFraction(BulletBody obj, float val);
588
589public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
590
591public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
592
593public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
594
595public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
596
597public abstract float GetCcdMotionThreshold(BulletBody obj);
598
599public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
600
601public abstract float GetCcdSweptSphereRadius(BulletBody obj);
602
603public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
604
605public abstract IntPtr GetUserPointer(BulletBody obj);
606
607public abstract void SetUserPointer(BulletBody obj, IntPtr val);
608
609// =====================================================================================
610// btRigidBody entries
611public abstract void ApplyGravity(BulletBody obj);
612
613public abstract void SetGravity(BulletBody obj, Vector3 val);
614
615public abstract Vector3 GetGravity(BulletBody obj);
616
617public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
618
619public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
620
621public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
622
623public abstract float GetLinearDamping(BulletBody obj);
624
625public abstract float GetAngularDamping(BulletBody obj);
626
627public abstract float GetLinearSleepingThreshold(BulletBody obj);
628
629public abstract void ApplyDamping(BulletBody obj, float timeStep);
630
631public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
632
633public abstract Vector3 GetLinearFactor(BulletBody obj);
634
635public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
636
637public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
638
639// Add a force to the object as if its mass is one.
640public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
641
642// Set the force being applied to the object as if its mass is one.
643public abstract void SetObjectForce(BulletBody obj, Vector3 force);
644
645public abstract Vector3 GetTotalForce(BulletBody obj);
646
647public abstract Vector3 GetTotalTorque(BulletBody obj);
648
649public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
650
651public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
652
653public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
654
655public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
656
657// Apply force at the given point. Will add torque to the object.
658public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
659
660// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
661public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
662
663// Apply impulse to the object's torque. Force is scaled by object's mass.
664public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
665
666// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
667public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
668
669public abstract void ClearForces(BulletBody obj);
670
671public abstract void ClearAllForces(BulletBody obj);
672
673public abstract void UpdateInertiaTensor(BulletBody obj);
674
675public abstract Vector3 GetLinearVelocity(BulletBody obj);
676
677public abstract Vector3 GetAngularVelocity(BulletBody obj);
678
679public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
680
681public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
682
683public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
684
685public abstract void Translate(BulletBody obj, Vector3 trans);
686
687public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
688
689public abstract bool WantsSleeping(BulletBody obj);
690
691public abstract void SetAngularFactor(BulletBody obj, float factor);
692
693public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
694
695public abstract Vector3 GetAngularFactor(BulletBody obj);
696
697public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
698
699public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
700
701public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
702
703public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
704
705public abstract int GetNumConstraintRefs(BulletBody obj);
706
707public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask);
708
709// =====================================================================================
710// btCollisionShape entries
711
712public abstract float GetAngularMotionDisc(BulletShape shape);
713
714public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
715
716public abstract bool IsPolyhedral(BulletShape shape);
717
718public abstract bool IsConvex2d(BulletShape shape);
719
720public abstract bool IsConvex(BulletShape shape);
721
722public abstract bool IsNonMoving(BulletShape shape);
723
724public abstract bool IsConcave(BulletShape shape);
725
726public abstract bool IsCompound(BulletShape shape);
727
728public abstract bool IsSoftBody(BulletShape shape);
729
730public abstract bool IsInfinite(BulletShape shape);
731
732public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
733
734public abstract Vector3 GetLocalScaling(BulletShape shape);
735
736public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
737
738public abstract int GetShapeType(BulletShape shape);
739
740public abstract void SetMargin(BulletShape shape, float val);
741
742public abstract float GetMargin(BulletShape shape);
743
744// =====================================================================================
745// Debugging
746public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
747
748public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
749
750public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
751
752public virtual void DumpActivationInfo(BulletWorld sim) { }
753
754public virtual void DumpAllInfo(BulletWorld sim) { }
755
756public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
757
758public virtual void ResetBroadphasePool(BulletWorld sim) { }
759
760public virtual void ResetConstraintSolver(BulletWorld sim) { }
761
762};
763}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
new file mode 100644
index 0000000..9c3f160
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
@@ -0,0 +1,813 @@
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 log4net;
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public sealed class BSCharacter : BSPhysObject
38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]";
41
42 // private bool _stopped;
43 private OMV.Vector3 _size;
44 private bool _grabbed;
45 private bool _selected;
46 private float _mass;
47 private float _avatarVolume;
48 private float _collisionScore;
49 private OMV.Vector3 _acceleration;
50 private int _physicsActorType;
51 private bool _isPhysical;
52 private bool _flying;
53 private bool _setAlwaysRun;
54 private bool _throttleUpdates;
55 private bool _floatOnWater;
56 private OMV.Vector3 _rotationalVelocity;
57 private bool _kinematic;
58 private float _buoyancy;
59
60 private BSActorAvatarMove m_moveActor;
61 private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
62
63 private OMV.Vector3 _PIDTarget;
64 private float _PIDTau;
65
66// public override OMV.Vector3 RawVelocity
67// { get { return base.RawVelocity; }
68// set {
69// if (value != base.RawVelocity)
70// Util.PrintCallStack();
71// Console.WriteLine("Set rawvel to {0}", value);
72// base.RawVelocity = value; }
73// }
74
75 // Avatars are always complete (in the physics engine sense)
76 public override bool IsIncomplete { get { return false; } }
77
78 public BSCharacter(
79 uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying)
80
81 : base(parent_scene, localID, avName, "BSCharacter")
82 {
83 _physicsActorType = (int)ActorTypes.Agent;
84 RawPosition = pos;
85
86 _flying = isFlying;
87 RawOrientation = OMV.Quaternion.Identity;
88 RawVelocity = vel;
89 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
90 Friction = BSParam.AvatarStandingFriction;
91 Density = BSParam.AvatarDensity;
92
93 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
94 // replace with the default values.
95 _size = size;
96 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
97 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
98
99 // The dimensions of the physical capsule are kept in the scale.
100 // Physics creates a unit capsule which is scaled by the physics engine.
101 Scale = ComputeAvatarScale(_size);
102 // set _avatarVolume and _mass based on capsule size, _density and Scale
103 ComputeAvatarVolumeAndMass();
104
105 DetailLog(
106 "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}",
107 LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel);
108
109 // do actual creation in taint time
110 PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
111 {
112 DetailLog("{0},BSCharacter.create,taint", LocalID);
113
114 // New body and shape into PhysBody and PhysShape
115 PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
116
117 // The avatar's movement is controlled by this motor that speeds up and slows down
118 // the avatar seeking to reach the motor's target speed.
119 // This motor runs as a prestep action for the avatar so it will keep the avatar
120 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
121 m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
122 PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
123
124 SetPhysicalProperties();
125
126 IsInitialized = true;
127 });
128 return;
129 }
130
131 // called when this character is being destroyed and the resources should be released
132 public override void Destroy()
133 {
134 IsInitialized = false;
135
136 base.Destroy();
137
138 DetailLog("{0},BSCharacter.Destroy", LocalID);
139 PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
140 {
141 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
142 PhysBody.Clear();
143 PhysShape.Dereference(PhysScene);
144 PhysShape = new BSShapeNull();
145 });
146 }
147
148 private void SetPhysicalProperties()
149 {
150 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
151
152 ForcePosition = RawPosition;
153
154 // Set the velocity
155 if (m_moveActor != null)
156 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
157
158 ForceVelocity = RawVelocity;
159 TargetVelocity = RawVelocity;
160
161 // This will enable or disable the flying buoyancy of the avatar.
162 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
163 Flying = _flying;
164
165 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
166 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
167 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
168 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
169 if (BSParam.CcdMotionThreshold > 0f)
170 {
171 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
172 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
173 }
174
175 UpdatePhysicalMassProperties(RawMass, false);
176
177 // Make so capsule does not fall over
178 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
179
180 // The avatar mover sets some parameters.
181 PhysicalActors.Refresh();
182
183 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
184
185 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
186
187 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
188 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
189 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
190
191 // Do this after the object has been added to the world
192 if (BSParam.AvatarToAvatarCollisionsByDefault)
193 PhysBody.collisionType = CollisionType.Avatar;
194 else
195 PhysBody.collisionType = CollisionType.PhantomToOthersAvatar;
196
197 PhysBody.ApplyCollisionMask(PhysScene);
198 }
199
200 public override void RequestPhysicsterseUpdate()
201 {
202 base.RequestPhysicsterseUpdate();
203 }
204
205 // No one calls this method so I don't know what it could possibly mean
206 public override bool Stopped { get { return false; } }
207
208 public override OMV.Vector3 Size {
209 get
210 {
211 // Avatar capsule size is kept in the scale parameter.
212 return _size;
213 }
214
215 set {
216 // This is how much the avatar size is changing. Positive means getting bigger.
217 // The avatar altitude must be adjusted for this change.
218 float heightChange = value.Z - _size.Z;
219
220 _size = value;
221 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
222 // replace with the default values.
223 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
224 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
225
226 Scale = ComputeAvatarScale(_size);
227 ComputeAvatarVolumeAndMass();
228 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
229 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
230
231 PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
232 {
233 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
234 {
235 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
236 UpdatePhysicalMassProperties(RawMass, true);
237
238 // Adjust the avatar's position to account for the increase/decrease in size
239 ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
240
241 // Make sure this change appears as a property update event
242 PhysScene.PE.PushUpdate(PhysBody);
243 }
244 });
245
246 }
247 }
248
249 public override PrimitiveBaseShape Shape
250 {
251 set { BaseShape = value; }
252 }
253
254 public override bool Grabbed {
255 set { _grabbed = value; }
256 }
257 public override bool Selected {
258 set { _selected = value; }
259 }
260 public override bool IsSelected
261 {
262 get { return _selected; }
263 }
264 public override void CrossingFailure() { return; }
265 public override void link(PhysicsActor obj) { return; }
266 public override void delink() { return; }
267
268 // Set motion values to zero.
269 // Do it to the properties so the values get set in the physics engine.
270 // Push the setting of the values to the viewer.
271 // Called at taint time!
272 public override void ZeroMotion(bool inTaintTime)
273 {
274 RawVelocity = OMV.Vector3.Zero;
275 _acceleration = OMV.Vector3.Zero;
276 _rotationalVelocity = OMV.Vector3.Zero;
277
278 // Zero some other properties directly into the physics engine
279 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
280 {
281 if (PhysBody.HasPhysicalBody)
282 PhysScene.PE.ClearAllForces(PhysBody);
283 });
284 }
285
286 public override void ZeroAngularMotion(bool inTaintTime)
287 {
288 _rotationalVelocity = OMV.Vector3.Zero;
289
290 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
291 {
292 if (PhysBody.HasPhysicalBody)
293 {
294 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
295 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
296 // The next also get rid of applied linear force but the linear velocity is untouched.
297 PhysScene.PE.ClearForces(PhysBody);
298 }
299 });
300 }
301
302
303 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
304
305 public override OMV.Vector3 Position {
306 get {
307 // Don't refetch the position because this function is called a zillion times
308 // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
309 return RawPosition;
310 }
311 set {
312 RawPosition = value;
313
314 PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
315 {
316 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
317 PositionSanityCheck();
318 ForcePosition = RawPosition;
319 });
320 }
321 }
322 public override OMV.Vector3 ForcePosition {
323 get {
324 RawPosition = PhysScene.PE.GetPosition(PhysBody);
325 return RawPosition;
326 }
327 set {
328 RawPosition = value;
329 if (PhysBody.HasPhysicalBody)
330 {
331 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
332 }
333 }
334 }
335
336
337 // Check that the current position is sane and, if not, modify the position to make it so.
338 // Check for being below terrain or on water.
339 // Returns 'true' of the position was made sane by some action.
340 private bool PositionSanityCheck()
341 {
342 bool ret = false;
343
344 // TODO: check for out of bounds
345 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
346 {
347 // The character is out of the known/simulated area.
348 // Force the avatar position to be within known. ScenePresence will use the position
349 // plus the velocity to decide if the avatar is moving out of the region.
350 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
351 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
352 return true;
353 }
354
355 // If below the ground, move the avatar up
356 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
357 if (Position.Z < terrainHeight)
358 {
359 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
360 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
361 ret = true;
362 }
363 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
364 {
365 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
366 if (Position.Z < waterHeight)
367 {
368 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
369 ret = true;
370 }
371 }
372
373 return ret;
374 }
375
376 // A version of the sanity check that also makes sure a new position value is
377 // pushed back to the physics engine. This routine would be used by anyone
378 // who is not already pushing the value.
379 private bool PositionSanityCheck(bool inTaintTime)
380 {
381 bool ret = false;
382 if (PositionSanityCheck())
383 {
384 // The new position value must be pushed into the physics engine but we can't
385 // just assign to "Position" because of potential call loops.
386 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
387 {
388 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
389 ForcePosition = RawPosition;
390 });
391 ret = true;
392 }
393 return ret;
394 }
395
396 public override float Mass { get { return _mass; } }
397
398 // used when we only want this prim's mass and not the linkset thing
399 public override float RawMass {
400 get {return _mass; }
401 }
402 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
403 {
404 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
405 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
406 }
407
408 public override OMV.Vector3 Force {
409 get { return RawForce; }
410 set {
411 RawForce = value;
412 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
413 PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
414 {
415 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
416 if (PhysBody.HasPhysicalBody)
417 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
418 });
419 }
420 }
421
422 // Avatars don't do vehicles
423 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
424 public override void VehicleFloatParam(int param, float value) { }
425 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
426 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
427 public override void VehicleFlags(int param, bool remove) { }
428
429 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
430 public override void SetVolumeDetect(int param) { return; }
431 public override bool IsVolumeDetect { get { return false; } }
432
433 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
434 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
435
436 // Sets the target in the motor. This starts the changing of the avatar's velocity.
437 public override OMV.Vector3 TargetVelocity
438 {
439 get
440 {
441 return base.m_targetVelocity;
442 }
443 set
444 {
445 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
446 m_targetVelocity = value;
447 OMV.Vector3 targetVel = value;
448 if (_setAlwaysRun && !_flying)
449 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f);
450
451 if (m_moveActor != null)
452 m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
453 }
454 }
455 // Directly setting velocity means this is what the user really wants now.
456 public override OMV.Vector3 Velocity {
457 get { return RawVelocity; }
458 set {
459 RawVelocity = value;
460 OMV.Vector3 vel = RawVelocity;
461
462 DetailLog("{0}: set Velocity = {1}", LocalID, value);
463
464 PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
465 {
466 if (m_moveActor != null)
467 m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */);
468
469 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel);
470 ForceVelocity = vel;
471 });
472 }
473 }
474
475 public override OMV.Vector3 ForceVelocity {
476 get { return RawVelocity; }
477 set {
478 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
479// Util.PrintCallStack();
480 DetailLog("{0}: set ForceVelocity = {1}", LocalID, value);
481
482 RawVelocity = value;
483 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
484 PhysScene.PE.Activate(PhysBody, true);
485 }
486 }
487
488 public override OMV.Vector3 Torque {
489 get { return RawTorque; }
490 set { RawTorque = value;
491 }
492 }
493
494 public override float CollisionScore {
495 get { return _collisionScore; }
496 set { _collisionScore = value;
497 }
498 }
499 public override OMV.Vector3 Acceleration {
500 get { return _acceleration; }
501 set { _acceleration = value; }
502 }
503 public override OMV.Quaternion Orientation {
504 get { return RawOrientation; }
505 set {
506 // Orientation is set zillions of times when an avatar is walking. It's like
507 // the viewer doesn't trust us.
508 if (RawOrientation != value)
509 {
510 RawOrientation = value;
511 PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
512 {
513 // Bullet assumes we know what we are doing when forcing orientation
514 // so it lets us go against all the rules and just compensates for them later.
515 // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
516 // This keeps us from flipping the capsule over which the veiwer does not understand.
517 float oRoll, oPitch, oYaw;
518 RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
519 OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
520 // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
521 // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation,
522 // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
523 ForceOrientation = trimmedOrientation;
524 });
525 }
526 }
527 }
528 // Go directly to Bullet to get/set the value.
529 public override OMV.Quaternion ForceOrientation
530 {
531 get
532 {
533 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
534 return RawOrientation;
535 }
536 set
537 {
538 RawOrientation = value;
539 if (PhysBody.HasPhysicalBody)
540 {
541 // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
542 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
543 }
544 }
545 }
546 public override int PhysicsActorType {
547 get { return _physicsActorType; }
548 set { _physicsActorType = value;
549 }
550 }
551 public override bool IsPhysical {
552 get { return _isPhysical; }
553 set { _isPhysical = value;
554 }
555 }
556 public override bool IsSolid {
557 get { return true; }
558 }
559 public override bool IsStatic {
560 get { return false; }
561 }
562 public override bool IsPhysicallyActive {
563 get { return true; }
564 }
565 public override bool Flying {
566 get { return _flying; }
567 set {
568 _flying = value;
569
570 // simulate flying by changing the effect of gravity
571 Buoyancy = ComputeBuoyancyFromFlying(_flying);
572 }
573 }
574 // Flying is implimented by changing the avatar's buoyancy.
575 // Would this be done better with a vehicle type?
576 private float ComputeBuoyancyFromFlying(bool ifFlying) {
577 return ifFlying ? 1f : 0f;
578 }
579 public override bool
580 SetAlwaysRun {
581 get { return _setAlwaysRun; }
582 set { _setAlwaysRun = value; }
583 }
584 public override bool ThrottleUpdates {
585 get { return _throttleUpdates; }
586 set { _throttleUpdates = value; }
587 }
588 public override bool FloatOnWater {
589 set {
590 _floatOnWater = value;
591 PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
592 {
593 if (PhysBody.HasPhysicalBody)
594 {
595 if (_floatOnWater)
596 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
597 else
598 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
599 }
600 });
601 }
602 }
603 public override OMV.Vector3 RotationalVelocity {
604 get { return _rotationalVelocity; }
605 set { _rotationalVelocity = value; }
606 }
607 public override OMV.Vector3 ForceRotationalVelocity {
608 get { return _rotationalVelocity; }
609 set { _rotationalVelocity = value; }
610 }
611 public override bool Kinematic {
612 get { return _kinematic; }
613 set { _kinematic = value; }
614 }
615 // neg=fall quickly, 0=1g, 1=0g, pos=float up
616 public override float Buoyancy {
617 get { return _buoyancy; }
618 set { _buoyancy = value;
619 PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
620 {
621 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
622 ForceBuoyancy = _buoyancy;
623 });
624 }
625 }
626 public override float ForceBuoyancy {
627 get { return _buoyancy; }
628 set {
629 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
630
631 _buoyancy = value;
632 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
633 // Buoyancy is faked by changing the gravity applied to the object
634 float grav = BSParam.Gravity * (1f - _buoyancy);
635 Gravity = new OMV.Vector3(0f, 0f, grav);
636 if (PhysBody.HasPhysicalBody)
637 PhysScene.PE.SetGravity(PhysBody, Gravity);
638 }
639 }
640
641 // Used for MoveTo
642 public override OMV.Vector3 PIDTarget {
643 set { _PIDTarget = value; }
644 }
645
646 public override bool PIDActive { get; set; }
647
648 public override float PIDTau {
649 set { _PIDTau = value; }
650 }
651
652 public override void AddForce(OMV.Vector3 force, bool pushforce)
653 {
654 // Since this force is being applied in only one step, make this a force per second.
655 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
656 AddForce(addForce, pushforce, false);
657 }
658 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
659 if (force.IsFinite())
660 {
661 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
662 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
663
664 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
665 {
666 // Bullet adds this central force to the total force for this tick
667 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
668 if (PhysBody.HasPhysicalBody)
669 {
670 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
671 }
672 });
673 }
674 else
675 {
676 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
677 return;
678 }
679 }
680
681 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
682 }
683 public override void SetMomentum(OMV.Vector3 momentum) {
684 }
685
686 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
687 {
688 OMV.Vector3 newScale = size;
689
690 // Bullet's capsule total height is the "passed height + radius * 2";
691 // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
692 // The number we pass in for 'scaling' is the multiplier to get that base
693 // shape to be the size desired.
694 // So, when creating the scale for the avatar height, we take the passed height
695 // (size.Z) and remove the caps.
696 // An oddity of the Bullet capsule implementation is that it presumes the Y
697 // dimension is the radius of the capsule. Even though some of the code allows
698 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
699
700 // Scale is multiplier of radius with one of "0.5"
701
702 float heightAdjust = BSParam.AvatarHeightMidFudge;
703 if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
704 {
705 const float AVATAR_LOW = 1.1f;
706 const float AVATAR_MID = 1.775f; // 1.87f
707 const float AVATAR_HI = 2.45f;
708 // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
709 float midHeightOffset = size.Z - AVATAR_MID;
710 if (midHeightOffset < 0f)
711 {
712 // Small avatar. Add the adjustment based on the distance from midheight
713 heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
714 }
715 else
716 {
717 // Large avatar. Add the adjustment based on the distance from midheight
718 heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
719 }
720 }
721 if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule)
722 {
723 newScale.X = size.X / 2f;
724 newScale.Y = size.Y / 2f;
725 // The total scale height is the central cylindar plus the caps on the two ends.
726 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
727 }
728 else
729 {
730 newScale.Z = size.Z + heightAdjust;
731 }
732 // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
733
734 // If smaller than the endcaps, just fake like we're almost that small
735 if (newScale.Z < 0)
736 newScale.Z = 0.1f;
737
738 DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
739 LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
740
741 return newScale;
742 }
743
744 // set _avatarVolume and _mass based on capsule size, _density and Scale
745 private void ComputeAvatarVolumeAndMass()
746 {
747 _avatarVolume = (float)(
748 Math.PI
749 * Size.X / 2f
750 * Size.Y / 2f // the area of capsule cylinder
751 * Size.Z // times height of capsule cylinder
752 + 1.33333333f
753 * Math.PI
754 * Size.X / 2f
755 * Math.Min(Size.X, Size.Y) / 2
756 * Size.Y / 2f // plus the volume of the capsule end caps
757 );
758 _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
759 }
760
761 // The physics engine says that properties have updated. Update same and inform
762 // the world that things have changed.
763 public override void UpdateProperties(EntityProperties entprop)
764 {
765 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
766 TriggerPreUpdatePropertyAction(ref entprop);
767
768 RawPosition = entprop.Position;
769 RawOrientation = entprop.Rotation;
770
771 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
772 // and will send agent updates to the clients if velocity changes by more than
773 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
774 // extra updates.
775 //
776 // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to
777 // avatar movement rather than removes it. The larger the threshold, the bigger the jitter.
778 // This is most noticeable in level flight and can be seen with
779 // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower
780 // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update
781 // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?)
782 // has not yet been identified.
783 //
784 // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra
785 // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients().
786// if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
787 RawVelocity = entprop.Velocity;
788
789 _acceleration = entprop.Acceleration;
790 _rotationalVelocity = entprop.RotationalVelocity;
791
792 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
793 if (PositionSanityCheck(true))
794 {
795 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
796 entprop.Position = RawPosition;
797 }
798
799 // remember the current and last set values
800 LastEntityProperties = CurrentEntityProperties;
801 CurrentEntityProperties = entprop;
802
803 // Tell the linkset about value changes
804 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
805
806 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
807 // PhysScene.PostUpdate(this);
808
809 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
810 LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
811 }
812}
813}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
new file mode 100755
index 0000000..b47e9a8
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
@@ -0,0 +1,144 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public abstract class BSConstraint : IDisposable
36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
39 protected BulletWorld m_world;
40 protected BSScene PhysicsScene;
41 protected BulletBody m_body1;
42 protected BulletBody m_body2;
43 protected BulletConstraint m_constraint;
44 protected bool m_enabled = false;
45
46 public BulletBody Body1 { get { return m_body1; } }
47 public BulletBody Body2 { get { return m_body2; } }
48 public BulletConstraint Constraint { get { return m_constraint; } }
49 public abstract ConstraintType Type { get; }
50 public bool IsEnabled { get { return m_enabled; } }
51
52 public BSConstraint(BulletWorld world)
53 {
54 m_world = world;
55 PhysicsScene = m_world.physicsScene;
56 }
57
58 public virtual void Dispose()
59 {
60 if (m_enabled)
61 {
62 m_enabled = false;
63 if (m_constraint.HasPhysicalConstraint)
64 {
65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
67 m_body1.ID,
68 m_body1.ID, m_body1.AddrString,
69 m_body2.ID, m_body2.AddrString,
70 success);
71 m_constraint.Clear();
72 }
73 }
74 }
75
76 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
77 {
78 bool ret = false;
79 if (m_enabled)
80 {
81 m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high);
82 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
83 }
84 return ret;
85 }
86
87 public virtual bool SetAngularLimits(Vector3 low, Vector3 high)
88 {
89 bool ret = false;
90 if (m_enabled)
91 {
92 m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high);
93 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
94 }
95 return ret;
96 }
97
98 public virtual bool SetSolverIterations(float cnt)
99 {
100 bool ret = false;
101 if (m_enabled)
102 {
103 PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt);
104 ret = true;
105 }
106 return ret;
107 }
108
109 public virtual bool CalculateTransforms()
110 {
111 bool ret = false;
112 if (m_enabled)
113 {
114 // Recompute the internal transforms
115 PhysicsScene.PE.CalculateTransforms(m_constraint);
116 ret = true;
117 }
118 return ret;
119 }
120
121 // Reset this constraint making sure it has all its internal structures
122 // recomputed and is enabled and ready to go.
123 public virtual bool RecomputeConstraintVariables(float mass)
124 {
125 bool ret = false;
126 if (m_enabled)
127 {
128 ret = CalculateTransforms();
129 if (ret)
130 {
131 // Setting an object's mass to zero (making it static like when it's selected)
132 // automatically disables the constraints.
133 // If the link is enabled, be sure to set the constraint itself to enabled.
134 PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true));
135 }
136 else
137 {
138 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
139 }
140 }
141 return ret;
142 }
143}
144}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
new file mode 100755
index 0000000..7fcb75c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
@@ -0,0 +1,180 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public class BSConstraint6Dof : BSConstraint
36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40
41 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world)
42 {
43 m_body1 = obj1;
44 m_body2 = obj2;
45 m_enabled = false;
46 }
47
48 // Create a btGeneric6DofConstraint
49 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
50 Vector3 frame1, Quaternion frame1rot,
51 Vector3 frame2, Quaternion frame2rot,
52 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
53 : base(world)
54 {
55 m_body1 = obj1;
56 m_body2 = obj2;
57 m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2,
58 frame1, frame1rot,
59 frame2, frame2rot,
60 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
61 m_enabled = true;
62 PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
63 m_body1.ID, world.worldID,
64 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
65 PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
66 m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
67 }
68
69 // 6 Dof constraint based on a midpoint between the two constrained bodies
70 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
71 Vector3 joinPoint,
72 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
73 : base(world)
74 {
75 m_body1 = obj1;
76 m_body2 = obj2;
77 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
78 {
79 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
80 BSScene.DetailLogZero, world.worldID,
81 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
82 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
83 LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
84 m_enabled = false;
85 }
86 else
87 {
88 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
89 joinPoint,
90 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
91
92 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
93 m_body1.ID, world.worldID, m_constraint.AddrString,
94 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
95
96 if (!m_constraint.HasPhysicalConstraint)
97 {
98 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
99 LogHeader, obj1.ID, obj2.ID);
100 m_enabled = false;
101 }
102 else
103 {
104 m_enabled = true;
105 }
106 }
107 }
108
109 // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object
110 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot,
111 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
112 : base(world)
113 {
114 m_body1 = obj1;
115 m_body2 = obj1; // Look out for confusion down the road
116 m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1,
117 frameInBloc, frameInBrot,
118 useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
119 m_enabled = true;
120 PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
121 m_body1.ID, world.worldID, obj1.ID, obj1.AddrString);
122 PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}",
123 m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
124 }
125
126 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
127 {
128 bool ret = false;
129 if (m_enabled)
130 {
131 PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
132 ret = true;
133 }
134 return ret;
135 }
136
137 public bool SetCFMAndERP(float cfm, float erp)
138 {
139 bool ret = false;
140 if (m_enabled)
141 {
142 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
143 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
144 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
145 ret = true;
146 }
147 return ret;
148 }
149
150 public bool UseFrameOffset(bool useOffset)
151 {
152 bool ret = false;
153 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
154 if (m_enabled)
155 ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
156 return ret;
157 }
158
159 public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
160 {
161 bool ret = false;
162 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
163 if (m_enabled)
164 {
165 ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
166 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
167 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
168 }
169 return ret;
170 }
171
172 public bool SetBreakingImpulseThreshold(float threshold)
173 {
174 bool ret = false;
175 if (m_enabled)
176 ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
177 return ret;
178 }
179}
180}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
new file mode 100755
index 0000000..5c8d94e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
@@ -0,0 +1,181 @@
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 log4net;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public sealed class BSConstraintCollection : IDisposable
37{
38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
40
41 delegate bool ConstraintAction(BSConstraint constrain);
42
43 private List<BSConstraint> m_constraints;
44 private BulletWorld m_world;
45
46 public BSConstraintCollection(BulletWorld world)
47 {
48 m_world = world;
49 m_constraints = new List<BSConstraint>();
50 }
51
52 public void Dispose()
53 {
54 this.Clear();
55 }
56
57 public void Clear()
58 {
59 lock (m_constraints)
60 {
61 foreach (BSConstraint cons in m_constraints)
62 {
63 cons.Dispose();
64 }
65 m_constraints.Clear();
66 }
67 }
68
69 public bool AddConstraint(BSConstraint cons)
70 {
71 lock (m_constraints)
72 {
73 // There is only one constraint between any bodies. Remove any old just to make sure.
74 RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
75
76 m_constraints.Add(cons);
77 }
78
79 return true;
80 }
81
82 // Get the constraint between two bodies. There can be only one.
83 // Return 'true' if a constraint was found.
84 public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
85 {
86 bool found = false;
87 BSConstraint foundConstraint = null;
88
89 uint lookingID1 = body1.ID;
90 uint lookingID2 = body2.ID;
91 lock (m_constraints)
92 {
93 foreach (BSConstraint constrain in m_constraints)
94 {
95 if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
96 || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
97 {
98 foundConstraint = constrain;
99 found = true;
100 break;
101 }
102 }
103 }
104 returnConstraint = foundConstraint;
105 return found;
106 }
107
108 // Remove any constraint between the passed bodies.
109 // Presumed there is only one such constraint possible.
110 // Return 'true' if a constraint was found and destroyed.
111 public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
112 {
113 bool ret = false;
114 lock (m_constraints)
115 {
116 BSConstraint constrain;
117 if (this.TryGetConstraint(body1, body2, out constrain))
118 {
119 // remove the constraint from our collection
120 ret = RemoveAndDestroyConstraint(constrain);
121 }
122 }
123
124 return ret;
125 }
126
127 // The constraint MUST exist in the collection
128 // Could be called if the constraint was previously removed.
129 // Return 'true' if the constraint was actually removed and disposed.
130 public bool RemoveAndDestroyConstraint(BSConstraint constrain)
131 {
132 bool removed = false;
133 lock (m_constraints)
134 {
135 // remove the constraint from our collection
136 removed = m_constraints.Remove(constrain);
137 }
138 // Dispose() is safe to call multiple times
139 constrain.Dispose();
140 return removed;
141 }
142
143 // Remove all constraints that reference the passed body.
144 // Return 'true' if any constraints were destroyed.
145 public bool RemoveAndDestroyConstraint(BulletBody body1)
146 {
147 List<BSConstraint> toRemove = new List<BSConstraint>();
148 uint lookingID = body1.ID;
149 lock (m_constraints)
150 {
151 foreach (BSConstraint constrain in m_constraints)
152 {
153 if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
154 {
155 toRemove.Add(constrain);
156 }
157 }
158 foreach (BSConstraint constrain in toRemove)
159 {
160 m_constraints.Remove(constrain);
161 constrain.Dispose();
162 }
163 }
164 return (toRemove.Count > 0);
165 }
166
167 public bool RecalculateAllConstraints()
168 {
169 bool ret = false;
170 lock (m_constraints)
171 {
172 foreach (BSConstraint constrain in m_constraints)
173 {
174 constrain.CalculateTransforms();
175 ret = true;
176 }
177 }
178 return ret;
179 }
180}
181}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
new file mode 100755
index 0000000..7a76a9a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
@@ -0,0 +1,54 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public sealed class BSConstraintConeTwist : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } }
38
39 public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frameInAloc, Quaternion frameInArot,
41 Vector3 frameInBloc, Quaternion frameInBrot,
42 bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2,
48 frameInAloc, frameInArot, frameInBloc, frameInBrot,
49 disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52}
53
54}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
new file mode 100755
index 0000000..ed89f63
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
@@ -0,0 +1,55 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public sealed class BSConstraintHinge : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38
39 public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 pivotInA, pivotInB, axisInA, axisInB,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52
53}
54
55}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
new file mode 100755
index 0000000..37cfa07
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
@@ -0,0 +1,55 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public sealed class BSConstraintSlider : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } }
38
39 public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frameInAloc, Quaternion frameInArot,
41 Vector3 frameInBloc, Quaternion frameInBrot,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2,
48 frameInAloc, frameInArot, frameInBloc, frameInBrot,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52
53}
54
55}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
new file mode 100755
index 0000000..8e7ddff
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
@@ -0,0 +1,103 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public sealed class BSConstraintSpring : BSConstraint6Dof
36{
37 public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } }
38
39 public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frame1Loc, Quaternion frame1Rot,
41 Vector3 frame2Loc, Quaternion frame2Rot,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 :base(world, obj1, obj2)
44 {
45 m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2,
46 frame1Loc, frame1Rot, frame2Loc, frame2Rot,
47 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
48 m_enabled = true;
49
50 PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
51 obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
52 PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
53 m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
54 }
55
56 public bool SetAxisEnable(int pIndex, bool pAxisEnable)
57 {
58 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}",
59 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable);
60 PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable));
61 return true;
62 }
63
64 public bool SetStiffness(int pIndex, float pStiffness)
65 {
66 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}",
67 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness);
68 PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness);
69 return true;
70 }
71
72 public bool SetDamping(int pIndex, float pDamping)
73 {
74 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}",
75 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping);
76 PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping);
77 return true;
78 }
79
80 public bool SetEquilibriumPoint(int pIndex, float pEqPoint)
81 {
82 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}",
83 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint);
84 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint);
85 return true;
86 }
87
88 public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq)
89 {
90 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}",
91 m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq);
92 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X);
93 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y);
94 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z);
95 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X);
96 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y);
97 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z);
98 return true;
99 }
100
101}
102
103} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
new file mode 100644
index 0000000..c6d6331
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
@@ -0,0 +1,1800 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
28 * are Copyright (c) 2009 Linden Research, Inc and are used under their license
29 * of Creative Commons Attribution-Share Alike 3.0
30 * (http://creativecommons.org/licenses/by-sa/3.0/).
31 */
32
33using System;
34using System.Collections.Generic;
35using System.Reflection;
36using System.Runtime.InteropServices;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Region.Physics.Manager;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43 public sealed class BSDynamics : BSActor
44 {
45#pragma warning disable 414
46 private static string LogHeader = "[BULLETSIM VEHICLE]";
47#pragma warning restore 414
48
49 // the prim this dynamic controller belongs to
50 private BSPrimLinkable ControllingPrim { get; set; }
51
52 private bool m_haveRegisteredForSceneEvents;
53
54 // mass of the vehicle fetched each time we're calles
55 private float m_vehicleMass;
56
57 // Vehicle properties
58 public Vehicle Type { get; set; }
59
60 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
61 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
62 // HOVER_TERRAIN_ONLY
63 // HOVER_GLOBAL_HEIGHT
64 // NO_DEFLECTION_UP
65 // HOVER_WATER_ONLY
66 // HOVER_UP_ONLY
67 // LIMIT_MOTOR_UP
68 // LIMIT_ROLL_ONLY
69 private Vector3 m_BlockingEndPoint = Vector3.Zero;
70 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
71 private Quaternion m_referenceFrame = Quaternion.Identity;
72
73 // Linear properties
74 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
75 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
76 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
78 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
79 private float m_linearMotorDecayTimescale = 1;
80 private float m_linearMotorTimescale = 1;
81 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
82 private Vector3 m_lastPositionVector = Vector3.Zero;
83 // private bool m_LinearMotorSetLastFrame = false;
84 // private Vector3 m_linearMotorOffset = Vector3.Zero;
85
86 //Angular properties
87 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
88 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
89 // private int m_angularMotorApply = 0; // application frame counter
90 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
91 private float m_angularMotorTimescale = 1; // motor angular velocity ramp up rate
92 private float m_angularMotorDecayTimescale = 1; // motor angular velocity decay rate
93 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
94 private Vector3 m_lastAngularVelocity = Vector3.Zero;
95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
96
97 //Deflection properties
98 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
99 private float m_angularDeflectionEfficiency = 0;
100 private float m_angularDeflectionTimescale = 0;
101 private float m_linearDeflectionEfficiency = 0;
102 private float m_linearDeflectionTimescale = 0;
103
104 //Banking properties
105 private float m_bankingEfficiency = 0;
106 private float m_bankingMix = 1;
107 private float m_bankingTimescale = 0;
108
109 //Hover and Buoyancy properties
110 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
111 private float m_VhoverHeight = 0f;
112 private float m_VhoverEfficiency = 0f;
113 private float m_VhoverTimescale = 0f;
114 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
115 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
116 private float m_VehicleBuoyancy = 0f;
117 private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set
118
119 //Attractor properties
120 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
121 private float m_verticalAttractionEfficiency = 1.0f; // damped
122 private float m_verticalAttractionCutoff = 500f; // per the documentation
123 // Timescale > cutoff means no vert attractor.
124 private float m_verticalAttractionTimescale = 510f;
125
126 // Just some recomputed constants:
127#pragma warning disable 414
128 static readonly float TwoPI = ((float)Math.PI) * 2f;
129 static readonly float FourPI = ((float)Math.PI) * 4f;
130 static readonly float PIOverFour = ((float)Math.PI) / 4f;
131 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
132#pragma warning restore 414
133
134 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
135 : base(myScene, myPrim, actorName)
136 {
137 Type = Vehicle.TYPE_NONE;
138 m_haveRegisteredForSceneEvents = false;
139
140 ControllingPrim = myPrim as BSPrimLinkable;
141 if (ControllingPrim == null)
142 {
143 // THIS CANNOT HAPPEN!!
144 }
145 VDetailLog("{0},Creation", ControllingPrim.LocalID);
146 }
147
148 // Return 'true' if this vehicle is doing vehicle things
149 public bool IsActive
150 {
151 get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); }
152 }
153
154 // Return 'true' if this a vehicle that should be sitting on the ground
155 public bool IsGroundVehicle
156 {
157 get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); }
158 }
159
160 #region Vehicle parameter setting
161 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
162 {
163 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
164 float clampTemp;
165
166 switch (pParam)
167 {
168 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
169 m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
170 break;
171 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
172 m_angularDeflectionTimescale = ClampInRange(0.25f, pValue, 120);
173 break;
174 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
175 m_angularMotorDecayTimescale = ClampInRange(0.25f, pValue, 120);
176 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
177 break;
178 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
179 m_angularMotorTimescale = ClampInRange(0.25f, pValue, 120);
180 m_angularMotor.TimeScale = m_angularMotorTimescale;
181 break;
182 case Vehicle.BANKING_EFFICIENCY:
183 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
184 break;
185 case Vehicle.BANKING_MIX:
186 m_bankingMix = ClampInRange(0.01f, pValue, 1);
187 break;
188 case Vehicle.BANKING_TIMESCALE:
189 m_bankingTimescale = ClampInRange(0.25f, pValue, 120);
190 break;
191 case Vehicle.BUOYANCY:
192 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
193 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
194 break;
195 case Vehicle.HOVER_EFFICIENCY:
196 m_VhoverEfficiency = ClampInRange(0.01f, pValue, 1f);
197 break;
198 case Vehicle.HOVER_HEIGHT:
199 m_VhoverHeight = ClampInRange(0f, pValue, 1000000f);
200 break;
201 case Vehicle.HOVER_TIMESCALE:
202 m_VhoverTimescale = ClampInRange(0.01f, pValue, 120);
203 break;
204 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
205 m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
206 break;
207 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
208 m_linearDeflectionTimescale = ClampInRange(0.01f, pValue, 120);
209 break;
210 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
211 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
212 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
213 break;
214 case Vehicle.LINEAR_MOTOR_TIMESCALE:
215 m_linearMotorTimescale = ClampInRange(0.01f, pValue, 120);
216 m_linearMotor.TimeScale = m_linearMotorTimescale;
217 break;
218 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
219 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
220 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
221 break;
222 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
223 m_verticalAttractionTimescale = ClampInRange(0.01f, pValue, 120);
224 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
225 break;
226
227 // These are vector properties but the engine lets you use a single float value to
228 // set all of the components to the same value
229 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
230 clampTemp = ClampInRange(0.01f, pValue, 120);
231 m_angularFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
232 break;
233 case Vehicle.ANGULAR_MOTOR_DIRECTION:
234 clampTemp = ClampInRange(-TwoPI, pValue, TwoPI);
235 m_angularMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
236 m_angularMotor.Zero();
237 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 clampTemp = ClampInRange(0.01f, pValue, 120);
241 m_linearFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
242 break;
243 case Vehicle.LINEAR_MOTOR_DIRECTION:
244 clampTemp = ClampInRange(-BSParam.MaxLinearVelocity, pValue, BSParam.MaxLinearVelocity);
245 m_linearMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
246 m_linearMotorDirectionLASTSET = new Vector3(clampTemp, clampTemp, clampTemp);
247 m_linearMotor.SetTarget(m_linearMotorDirection);
248 break;
249 case Vehicle.LINEAR_MOTOR_OFFSET:
250 clampTemp = ClampInRange(-1000, pValue, 1000);
251 m_linearMotorOffset = new Vector3(clampTemp, clampTemp, clampTemp);
252 break;
253
254 }
255 }//end ProcessFloatVehicleParam
256
257 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
258 {
259 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
260 switch (pParam)
261 {
262 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
263 pValue.X = ClampInRange(0.25f, pValue.X, 120);
264 pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
265 pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
266 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
267 break;
268 case Vehicle.ANGULAR_MOTOR_DIRECTION:
269 // Limit requested angular speed to 2 rps= 4 pi rads/sec
270 pValue.X = ClampInRange(-FourPI, pValue.X, FourPI);
271 pValue.Y = ClampInRange(-FourPI, pValue.Y, FourPI);
272 pValue.Z = ClampInRange(-FourPI, pValue.Z, FourPI);
273 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
274 m_angularMotor.Zero();
275 m_angularMotor.SetTarget(m_angularMotorDirection);
276 break;
277 case Vehicle.LINEAR_FRICTION_TIMESCALE:
278 pValue.X = ClampInRange(0.25f, pValue.X, 120);
279 pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
280 pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
281 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
282 break;
283 case Vehicle.LINEAR_MOTOR_DIRECTION:
284 pValue.X = ClampInRange(-BSParam.MaxLinearVelocity, pValue.X, BSParam.MaxLinearVelocity);
285 pValue.Y = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Y, BSParam.MaxLinearVelocity);
286 pValue.Z = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Z, BSParam.MaxLinearVelocity);
287 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
288 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
289 m_linearMotor.SetTarget(m_linearMotorDirection);
290 break;
291 case Vehicle.LINEAR_MOTOR_OFFSET:
292 // Not sure the correct range to limit this variable
293 pValue.X = ClampInRange(-1000, pValue.X, 1000);
294 pValue.Y = ClampInRange(-1000, pValue.Y, 1000);
295 pValue.Z = ClampInRange(-1000, pValue.Z, 1000);
296 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
297 break;
298 case Vehicle.BLOCK_EXIT:
299 // Not sure the correct range to limit this variable
300 pValue.X = ClampInRange(-10000, pValue.X, 10000);
301 pValue.Y = ClampInRange(-10000, pValue.Y, 10000);
302 pValue.Z = ClampInRange(-10000, pValue.Z, 10000);
303 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
304 break;
305 }
306 }//end ProcessVectorVehicleParam
307
308 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
309 {
310 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
311 switch (pParam)
312 {
313 case Vehicle.REFERENCE_FRAME:
314 m_referenceFrame = pValue;
315 break;
316 case Vehicle.ROLL_FRAME:
317 m_RollreferenceFrame = pValue;
318 break;
319 }
320 }//end ProcessRotationVehicleParam
321
322 internal void ProcessVehicleFlags(int pParam, bool remove)
323 {
324 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove);
325 VehicleFlag parm = (VehicleFlag)pParam;
326 if (pParam == -1)
327 m_flags = (VehicleFlag)0;
328 else
329 {
330 if (remove)
331 m_flags &= ~parm;
332 else
333 m_flags |= parm;
334 }
335 }
336
337 public void ProcessTypeChange(Vehicle pType)
338 {
339 VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType);
340 // Set Defaults For Type
341 Type = pType;
342 switch (pType)
343 {
344 case Vehicle.TYPE_NONE:
345 m_linearMotorDirection = Vector3.Zero;
346 m_linearMotorTimescale = 0;
347 m_linearMotorDecayTimescale = 0;
348 m_linearFrictionTimescale = new Vector3(0, 0, 0);
349
350 m_angularMotorDirection = Vector3.Zero;
351 m_angularMotorDecayTimescale = 0;
352 m_angularMotorTimescale = 0;
353 m_angularFrictionTimescale = new Vector3(0, 0, 0);
354
355 m_VhoverHeight = 0;
356 m_VhoverEfficiency = 0;
357 m_VhoverTimescale = 0;
358 m_VehicleBuoyancy = 0;
359
360 m_linearDeflectionEfficiency = 1;
361 m_linearDeflectionTimescale = 1;
362
363 m_angularDeflectionEfficiency = 0;
364 m_angularDeflectionTimescale = 1000;
365
366 m_verticalAttractionEfficiency = 0;
367 m_verticalAttractionTimescale = 0;
368
369 m_bankingEfficiency = 0;
370 m_bankingTimescale = 1000;
371 m_bankingMix = 1;
372
373 m_referenceFrame = Quaternion.Identity;
374 m_flags = (VehicleFlag)0;
375
376 break;
377
378 case Vehicle.TYPE_SLED:
379 m_linearMotorDirection = Vector3.Zero;
380 m_linearMotorTimescale = 1000;
381 m_linearMotorDecayTimescale = 120;
382 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
383
384 m_angularMotorDirection = Vector3.Zero;
385 m_angularMotorTimescale = 1000;
386 m_angularMotorDecayTimescale = 120;
387 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
388
389 m_VhoverHeight = 0;
390 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
391 m_VhoverTimescale = 10;
392 m_VehicleBuoyancy = 0;
393
394 m_linearDeflectionEfficiency = 1;
395 m_linearDeflectionTimescale = 1;
396
397 m_angularDeflectionEfficiency = 1;
398 m_angularDeflectionTimescale = 1000;
399
400 m_verticalAttractionEfficiency = 0;
401 m_verticalAttractionTimescale = 0;
402
403 m_bankingEfficiency = 0;
404 m_bankingTimescale = 10;
405 m_bankingMix = 1;
406
407 m_referenceFrame = Quaternion.Identity;
408 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
409 | VehicleFlag.HOVER_TERRAIN_ONLY
410 | VehicleFlag.HOVER_GLOBAL_HEIGHT
411 | VehicleFlag.HOVER_UP_ONLY);
412 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
413 | VehicleFlag.LIMIT_ROLL_ONLY
414 | VehicleFlag.LIMIT_MOTOR_UP);
415
416 break;
417 case Vehicle.TYPE_CAR:
418 m_linearMotorDirection = Vector3.Zero;
419 m_linearMotorTimescale = 1;
420 m_linearMotorDecayTimescale = 60;
421 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
422
423 m_angularMotorDirection = Vector3.Zero;
424 m_angularMotorTimescale = 1;
425 m_angularMotorDecayTimescale = 0.8f;
426 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
427
428 m_VhoverHeight = 0;
429 m_VhoverEfficiency = 0;
430 m_VhoverTimescale = 1000;
431 m_VehicleBuoyancy = 0;
432
433 m_linearDeflectionEfficiency = 1;
434 m_linearDeflectionTimescale = 2;
435
436 m_angularDeflectionEfficiency = 0;
437 m_angularDeflectionTimescale = 10;
438
439 m_verticalAttractionEfficiency = 1f;
440 m_verticalAttractionTimescale = 10f;
441
442 m_bankingEfficiency = -0.2f;
443 m_bankingMix = 1;
444 m_bankingTimescale = 1;
445
446 m_referenceFrame = Quaternion.Identity;
447 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
448 | VehicleFlag.HOVER_TERRAIN_ONLY
449 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
450 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
451 | VehicleFlag.LIMIT_ROLL_ONLY
452 | VehicleFlag.LIMIT_MOTOR_UP
453 | VehicleFlag.HOVER_UP_ONLY);
454 break;
455 case Vehicle.TYPE_BOAT:
456 m_linearMotorDirection = Vector3.Zero;
457 m_linearMotorTimescale = 5;
458 m_linearMotorDecayTimescale = 60;
459 m_linearFrictionTimescale = new Vector3(10, 3, 2);
460
461 m_angularMotorDirection = Vector3.Zero;
462 m_angularMotorTimescale = 4;
463 m_angularMotorDecayTimescale = 4;
464 m_angularFrictionTimescale = new Vector3(10,10,10);
465
466 m_VhoverHeight = 0;
467 m_VhoverEfficiency = 0.5f;
468 m_VhoverTimescale = 2;
469 m_VehicleBuoyancy = 1;
470
471 m_linearDeflectionEfficiency = 0.5f;
472 m_linearDeflectionTimescale = 3;
473
474 m_angularDeflectionEfficiency = 0.5f;
475 m_angularDeflectionTimescale = 5;
476
477 m_verticalAttractionEfficiency = 0.5f;
478 m_verticalAttractionTimescale = 5f;
479
480 m_bankingEfficiency = -0.3f;
481 m_bankingMix = 0.8f;
482 m_bankingTimescale = 1;
483
484 m_referenceFrame = Quaternion.Identity;
485 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
486 | VehicleFlag.HOVER_GLOBAL_HEIGHT
487 | VehicleFlag.LIMIT_ROLL_ONLY
488 | VehicleFlag.HOVER_UP_ONLY);
489 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
490 | VehicleFlag.LIMIT_MOTOR_UP
491 | VehicleFlag.HOVER_WATER_ONLY);
492 break;
493 case Vehicle.TYPE_AIRPLANE:
494 m_linearMotorDirection = Vector3.Zero;
495 m_linearMotorTimescale = 2;
496 m_linearMotorDecayTimescale = 60;
497 m_linearFrictionTimescale = new Vector3(200, 10, 5);
498
499 m_angularMotorDirection = Vector3.Zero;
500 m_angularMotorTimescale = 4;
501 m_angularMotorDecayTimescale = 4;
502 m_angularFrictionTimescale = new Vector3(20, 20, 20);
503
504 m_VhoverHeight = 0;
505 m_VhoverEfficiency = 0.5f;
506 m_VhoverTimescale = 1000;
507 m_VehicleBuoyancy = 0;
508
509 m_linearDeflectionEfficiency = 0.5f;
510 m_linearDeflectionTimescale = 3;
511
512 m_angularDeflectionEfficiency = 1;
513 m_angularDeflectionTimescale = 2;
514
515 m_verticalAttractionEfficiency = 0.9f;
516 m_verticalAttractionTimescale = 2f;
517
518 m_bankingEfficiency = 1;
519 m_bankingMix = 0.7f;
520 m_bankingTimescale = 2;
521
522 m_referenceFrame = Quaternion.Identity;
523 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
524 | VehicleFlag.HOVER_TERRAIN_ONLY
525 | VehicleFlag.HOVER_GLOBAL_HEIGHT
526 | VehicleFlag.HOVER_UP_ONLY
527 | VehicleFlag.NO_DEFLECTION_UP
528 | VehicleFlag.LIMIT_MOTOR_UP);
529 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
530 break;
531 case Vehicle.TYPE_BALLOON:
532 m_linearMotorDirection = Vector3.Zero;
533 m_linearMotorTimescale = 5;
534 m_linearFrictionTimescale = new Vector3(5, 5, 5);
535 m_linearMotorDecayTimescale = 60;
536
537 m_angularMotorDirection = Vector3.Zero;
538 m_angularMotorTimescale = 6;
539 m_angularFrictionTimescale = new Vector3(10, 10, 10);
540 m_angularMotorDecayTimescale = 10;
541
542 m_VhoverHeight = 5;
543 m_VhoverEfficiency = 0.8f;
544 m_VhoverTimescale = 10;
545 m_VehicleBuoyancy = 1;
546
547 m_linearDeflectionEfficiency = 0;
548 m_linearDeflectionTimescale = 5;
549
550 m_angularDeflectionEfficiency = 0;
551 m_angularDeflectionTimescale = 5;
552
553 m_verticalAttractionEfficiency = 1f;
554 m_verticalAttractionTimescale = 100f;
555
556 m_bankingEfficiency = 0;
557 m_bankingMix = 0.7f;
558 m_bankingTimescale = 5;
559
560 m_referenceFrame = Quaternion.Identity;
561
562 m_referenceFrame = Quaternion.Identity;
563 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
564 | VehicleFlag.HOVER_TERRAIN_ONLY
565 | VehicleFlag.HOVER_UP_ONLY
566 | VehicleFlag.NO_DEFLECTION_UP
567 | VehicleFlag.LIMIT_MOTOR_UP);
568 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
569 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
570 break;
571 }
572
573 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f);
574 // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
575
576 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f);
577 // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
578
579 /* Not implemented
580 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
581 BSMotor.Infinite, BSMotor.InfiniteVector,
582 m_verticalAttractionEfficiency);
583 // Z goes away and we keep X and Y
584 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
585 */
586
587 if (this.Type == Vehicle.TYPE_NONE)
588 {
589 UnregisterForSceneEvents();
590 }
591 else
592 {
593 RegisterForSceneEvents();
594 }
595
596 // Update any physical parameters based on this type.
597 Refresh();
598 }
599 #endregion // Vehicle parameter setting
600
601 // BSActor.Refresh()
602 public override void Refresh()
603 {
604 // If asking for a refresh, reset the physical parameters before the next simulation step.
605 // Called whether active or not since the active state may be updated before the next step.
606 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
607 {
608 SetPhysicalParameters();
609 });
610 }
611
612 // Some of the properties of this prim may have changed.
613 // Do any updating needed for a vehicle
614 private void SetPhysicalParameters()
615 {
616 if (IsActive)
617 {
618 // Remember the mass so we don't have to fetch it every step
619 m_vehicleMass = ControllingPrim.TotalMass;
620
621 // Friction affects are handled by this vehicle code
622 // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
623 // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
624 ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
625 ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
626
627 // Moderate angular movement introduced by Bullet.
628 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
629 // Maybe compute linear and angular factor and damping from params.
630 m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping);
631 m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor);
632 m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
633
634 // Vehicles report collision events so we know when it's on the ground
635 // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
636 ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
637
638 // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
639 // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
640 // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
641 // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
642 ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass);
643
644 // Set the gravity for the vehicle depending on the buoyancy
645 // TODO: what should be done if prim and vehicle buoyancy differ?
646 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
647 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
648 // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
649 ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
650
651 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
652 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
653 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
654 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
655 );
656 }
657 else
658 {
659 if (ControllingPrim.PhysBody.HasPhysicalBody)
660 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
661 // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
662 }
663 }
664
665 // BSActor.RemoveBodyDependencies
666 public override void RemoveDependencies()
667 {
668 Refresh();
669 }
670
671 // BSActor.Release()
672 public override void Dispose()
673 {
674 VDetailLog("{0},Dispose", ControllingPrim.LocalID);
675 UnregisterForSceneEvents();
676 Type = Vehicle.TYPE_NONE;
677 Enabled = false;
678 return;
679 }
680
681 private void RegisterForSceneEvents()
682 {
683 if (!m_haveRegisteredForSceneEvents)
684 {
685 m_physicsScene.BeforeStep += this.Step;
686 m_physicsScene.AfterStep += this.PostStep;
687 ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty;
688 m_haveRegisteredForSceneEvents = true;
689 }
690 }
691
692 private void UnregisterForSceneEvents()
693 {
694 if (m_haveRegisteredForSceneEvents)
695 {
696 m_physicsScene.BeforeStep -= this.Step;
697 m_physicsScene.AfterStep -= this.PostStep;
698 ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty;
699 m_haveRegisteredForSceneEvents = false;
700 }
701 }
702
703 private void PreUpdateProperty(ref EntityProperties entprop)
704 {
705 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
706 // TODO: handle physics introduced by Bullet with computed vehicle physics.
707 if (IsActive)
708 {
709 entprop.RotationalVelocity = Vector3.Zero;
710 }
711 }
712
713 #region Known vehicle value functions
714 // Vehicle physical parameters that we buffer from constant getting and setting.
715 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
716 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
717 // This does two things: 1) saves continuious calls into unmanaged code, and
718 // 2) signals when a physics property update must happen back to the simulator
719 // to update values modified for the vehicle.
720 private int m_knownChanged;
721 private int m_knownHas;
722 private float m_knownTerrainHeight;
723 private float m_knownWaterLevel;
724 private Vector3 m_knownPosition;
725 private Vector3 m_knownVelocity;
726 private Vector3 m_knownForce;
727 private Vector3 m_knownForceImpulse;
728 private Quaternion m_knownOrientation;
729 private Vector3 m_knownRotationalVelocity;
730 private Vector3 m_knownRotationalForce;
731 private Vector3 m_knownRotationalImpulse;
732
733 private const int m_knownChangedPosition = 1 << 0;
734 private const int m_knownChangedVelocity = 1 << 1;
735 private const int m_knownChangedForce = 1 << 2;
736 private const int m_knownChangedForceImpulse = 1 << 3;
737 private const int m_knownChangedOrientation = 1 << 4;
738 private const int m_knownChangedRotationalVelocity = 1 << 5;
739 private const int m_knownChangedRotationalForce = 1 << 6;
740 private const int m_knownChangedRotationalImpulse = 1 << 7;
741 private const int m_knownChangedTerrainHeight = 1 << 8;
742 private const int m_knownChangedWaterLevel = 1 << 9;
743
744 public void ForgetKnownVehicleProperties()
745 {
746 m_knownHas = 0;
747 m_knownChanged = 0;
748 }
749 // Push all the changed values back into the physics engine
750 public void PushKnownChanged()
751 {
752 if (m_knownChanged != 0)
753 {
754 if ((m_knownChanged & m_knownChangedPosition) != 0)
755 ControllingPrim.ForcePosition = m_knownPosition;
756
757 if ((m_knownChanged & m_knownChangedOrientation) != 0)
758 ControllingPrim.ForceOrientation = m_knownOrientation;
759
760 if ((m_knownChanged & m_knownChangedVelocity) != 0)
761 {
762 ControllingPrim.ForceVelocity = m_knownVelocity;
763 // Fake out Bullet by making it think the velocity is the same as last time.
764 // Bullet does a bunch of smoothing for changing parameters.
765 // Since the vehicle is demanding this setting, we override Bullet's smoothing
766 // by telling Bullet the value was the same last time.
767 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
768 }
769
770 if ((m_knownChanged & m_knownChangedForce) != 0)
771 ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
772
773 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
774 ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
775
776 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
777 {
778 ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity;
779 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
780 }
781
782 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
783 ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
784
785 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
786 {
787 ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
788 }
789
790 // If we set one of the values (ie, the physics engine didn't do it) we must force
791 // an UpdateProperties event to send the changes up to the simulator.
792 m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody);
793 }
794 m_knownChanged = 0;
795 }
796
797 // Since the computation of terrain height can be a little involved, this routine
798 // is used to fetch the height only once for each vehicle simulation step.
799 Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1);
800 private float GetTerrainHeight(Vector3 pos)
801 {
802 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
803 {
804 lastRememberedHeightPos = pos;
805 m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
806 m_knownHas |= m_knownChangedTerrainHeight;
807 }
808 return m_knownTerrainHeight;
809 }
810
811 // Since the computation of water level can be a little involved, this routine
812 // is used ot fetch the level only once for each vehicle simulation step.
813 Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1);
814 private float GetWaterLevel(Vector3 pos)
815 {
816 if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos)
817 {
818 lastRememberedWaterHeightPos = pos;
819 m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
820 m_knownHas |= m_knownChangedWaterLevel;
821 }
822 return m_knownWaterLevel;
823 }
824
825 private Vector3 VehiclePosition
826 {
827 get
828 {
829 if ((m_knownHas & m_knownChangedPosition) == 0)
830 {
831 m_knownPosition = ControllingPrim.ForcePosition;
832 m_knownHas |= m_knownChangedPosition;
833 }
834 return m_knownPosition;
835 }
836 set
837 {
838 m_knownPosition = value;
839 m_knownChanged |= m_knownChangedPosition;
840 m_knownHas |= m_knownChangedPosition;
841 }
842 }
843
844 private Quaternion VehicleOrientation
845 {
846 get
847 {
848 if ((m_knownHas & m_knownChangedOrientation) == 0)
849 {
850 m_knownOrientation = ControllingPrim.ForceOrientation;
851 m_knownHas |= m_knownChangedOrientation;
852 }
853 return m_knownOrientation;
854 }
855 set
856 {
857 m_knownOrientation = value;
858 m_knownChanged |= m_knownChangedOrientation;
859 m_knownHas |= m_knownChangedOrientation;
860 }
861 }
862
863 private Vector3 VehicleVelocity
864 {
865 get
866 {
867 if ((m_knownHas & m_knownChangedVelocity) == 0)
868 {
869 m_knownVelocity = ControllingPrim.ForceVelocity;
870 m_knownHas |= m_knownChangedVelocity;
871 }
872 return m_knownVelocity;
873 }
874 set
875 {
876 m_knownVelocity = value;
877 m_knownChanged |= m_knownChangedVelocity;
878 m_knownHas |= m_knownChangedVelocity;
879 }
880 }
881
882 private void VehicleAddForce(Vector3 pForce)
883 {
884 if ((m_knownHas & m_knownChangedForce) == 0)
885 {
886 m_knownForce = Vector3.Zero;
887 m_knownHas |= m_knownChangedForce;
888 }
889 m_knownForce += pForce;
890 m_knownChanged |= m_knownChangedForce;
891 }
892
893 private void VehicleAddForceImpulse(Vector3 pImpulse)
894 {
895 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
896 {
897 m_knownForceImpulse = Vector3.Zero;
898 m_knownHas |= m_knownChangedForceImpulse;
899 }
900 m_knownForceImpulse += pImpulse;
901 m_knownChanged |= m_knownChangedForceImpulse;
902 }
903
904 private Vector3 VehicleRotationalVelocity
905 {
906 get
907 {
908 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
909 {
910 m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity;
911 m_knownHas |= m_knownChangedRotationalVelocity;
912 }
913 return (Vector3)m_knownRotationalVelocity;
914 }
915 set
916 {
917 m_knownRotationalVelocity = value;
918 m_knownChanged |= m_knownChangedRotationalVelocity;
919 m_knownHas |= m_knownChangedRotationalVelocity;
920 }
921 }
922 private void VehicleAddAngularForce(Vector3 aForce)
923 {
924 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
925 {
926 m_knownRotationalForce = Vector3.Zero;
927 }
928 m_knownRotationalForce += aForce;
929 m_knownChanged |= m_knownChangedRotationalForce;
930 m_knownHas |= m_knownChangedRotationalForce;
931 }
932 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
933 {
934 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
935 {
936 m_knownRotationalImpulse = Vector3.Zero;
937 m_knownHas |= m_knownChangedRotationalImpulse;
938 }
939 m_knownRotationalImpulse += pImpulse;
940 m_knownChanged |= m_knownChangedRotationalImpulse;
941 }
942
943 // Vehicle relative forward velocity
944 private Vector3 VehicleForwardVelocity
945 {
946 get
947 {
948 return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleFrameOrientation));
949 }
950 }
951
952 private float VehicleForwardSpeed
953 {
954 get
955 {
956 return VehicleForwardVelocity.X;
957 }
958 }
959 private Quaternion VehicleFrameOrientation
960 {
961 get
962 {
963 return VehicleOrientation * m_referenceFrame;
964 }
965 }
966
967 #endregion // Known vehicle value functions
968
969 // One step of the vehicle properties for the next 'pTimestep' seconds.
970 internal void Step(float pTimestep)
971 {
972 if (!IsActive) return;
973
974 ForgetKnownVehicleProperties();
975
976 MoveLinear(pTimestep);
977 MoveAngular(pTimestep);
978
979 LimitRotation(pTimestep);
980
981 // remember the position so next step we can limit absolute movement effects
982 m_lastPositionVector = VehiclePosition;
983
984 // If we forced the changing of some vehicle parameters, update the values and
985 // for the physics engine to note the changes so an UpdateProperties event will happen.
986 PushKnownChanged();
987
988 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
989 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
990
991 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
992 ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
993 }
994
995 // Called after the simulation step
996 internal void PostStep(float pTimestep)
997 {
998 if (!IsActive) return;
999
1000 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
1001 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
1002 }
1003
1004 // Apply the effect of the linear motor and other linear motions (like hover and float).
1005 private void MoveLinear(float pTimestep)
1006 {
1007 ComputeLinearVelocity(pTimestep);
1008
1009 ComputeLinearDeflection(pTimestep);
1010
1011 ComputeLinearTerrainHeightCorrection(pTimestep);
1012
1013 ComputeLinearHover(pTimestep);
1014
1015 ComputeLinearBlockingEndPoint(pTimestep);
1016
1017 ComputeLinearMotorUp(pTimestep);
1018
1019 ApplyGravity(pTimestep);
1020
1021 // If not changing some axis, reduce out velocity
1022 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
1023 {
1024 Vector3 vel = VehicleVelocity;
1025 if ((m_flags & (VehicleFlag.NO_X)) != 0)
1026 {
1027 vel.X = 0;
1028 }
1029 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
1030 {
1031 vel.Y = 0;
1032 }
1033 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
1034 {
1035 vel.Z = 0;
1036 }
1037 VehicleVelocity = vel;
1038 }
1039
1040 // ==================================================================
1041 // Clamp high or low velocities
1042 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
1043 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared)
1044 {
1045 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
1046 VehicleVelocity /= VehicleVelocity.Length();
1047 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
1048 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
1049 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
1050 }
1051 else if (newVelocityLengthSq < BSParam.VehicleMinLinearVelocitySquared)
1052 {
1053 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
1054 VDetailLog("{0}, MoveLinear,clampMin,origVelW={1},lenSq={2}",
1055 ControllingPrim.LocalID, origVelW, newVelocityLengthSq);
1056 VehicleVelocity = Vector3.Zero;
1057 }
1058
1059 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
1060
1061 } // end MoveLinear()
1062
1063 public void ComputeLinearVelocity(float pTimestep)
1064 {
1065 // Step the motor from the current value. Get the correction needed this step.
1066 Vector3 origVelW = VehicleVelocity; // DEBUG
1067 Vector3 currentVelV = VehicleForwardVelocity;
1068 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
1069
1070 // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction.
1071 Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep);
1072 linearMotorCorrectionV -= (currentVelV * frictionFactorV);
1073
1074 // Motor is vehicle coordinates. Rotate it to world coordinates
1075 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleFrameOrientation;
1076
1077 // If we're a ground vehicle, don't add any upward Z movement
1078 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
1079 {
1080 if (linearMotorVelocityW.Z > 0f)
1081 linearMotorVelocityW.Z = 0f;
1082 }
1083
1084 // Add this correction to the velocity to make it faster/slower.
1085 VehicleVelocity += linearMotorVelocityW;
1086
1087 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
1088 ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
1089 linearMotorVelocityW, VehicleVelocity, frictionFactorV);
1090 }
1091
1092 //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis
1093 //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity
1094 private void ComputeLinearDeflection(float pTimestep)
1095 {
1096 Vector3 linearDeflectionV = Vector3.Zero;
1097 Vector3 velocityV = VehicleForwardVelocity;
1098
1099 if (BSParam.VehicleEnableLinearDeflection)
1100 {
1101 // Velocity in Y and Z dimensions is movement to the side or turning.
1102 // Compute deflection factor from the to the side and rotational velocity
1103 linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y);
1104 linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z);
1105
1106 // Velocity to the side and around is corrected and moved into the forward direction
1107 linearDeflectionV.X += Math.Abs(linearDeflectionV.Y);
1108 linearDeflectionV.X += Math.Abs(linearDeflectionV.Z);
1109
1110 // Scale the deflection to the fractional simulation time
1111 linearDeflectionV *= pTimestep;
1112
1113 // Subtract the sideways and rotational velocity deflection factors while adding the correction forward
1114 linearDeflectionV *= new Vector3(1, -1, -1);
1115
1116 // Correction is vehicle relative. Convert to world coordinates.
1117 Vector3 linearDeflectionW = linearDeflectionV * VehicleFrameOrientation;
1118
1119 // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
1120 if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision)
1121 {
1122 linearDeflectionW.Z = 0f;
1123 }
1124
1125 VehicleVelocity += linearDeflectionW;
1126
1127 VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}",
1128 ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV);
1129 }
1130 }
1131
1132 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
1133 {
1134 // If below the terrain, move us above the ground a little.
1135 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
1136 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
1137 {
1138 // Force position because applying force won't get the vehicle through the terrain
1139 Vector3 newPosition = VehiclePosition;
1140 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
1141 VehiclePosition = newPosition;
1142 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
1143 ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
1144 }
1145 }
1146
1147 public void ComputeLinearHover(float pTimestep)
1148 {
1149 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
1150 // m_VhoverTimescale: time to achieve height
1151 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0 && (m_VhoverHeight > 0) && (m_VhoverTimescale < 300))
1152 {
1153 // We should hover, get the target height
1154 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
1155 {
1156 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
1157 }
1158 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
1159 {
1160 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
1161 }
1162 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
1163 {
1164 m_VhoverTargetHeight = m_VhoverHeight;
1165 }
1166 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
1167 {
1168 // If body is already heigher, use its height as target height
1169 if (VehiclePosition.Z > m_VhoverTargetHeight)
1170 {
1171 m_VhoverTargetHeight = VehiclePosition.Z;
1172
1173 // A 'misfeature' of this flag is that if the vehicle is above it's hover height,
1174 // the vehicle's buoyancy goes away. This is an SL bug that got used by so many
1175 // scripts that it could not be changed.
1176 // So, if above the height, reapply gravity if buoyancy had it turned off.
1177 if (m_VehicleBuoyancy != 0)
1178 {
1179 Vector3 appliedGravity = ControllingPrim.ComputeGravity(ControllingPrim.Buoyancy) * m_vehicleMass;
1180 VehicleAddForce(appliedGravity);
1181 }
1182 }
1183 }
1184
1185 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
1186 {
1187 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
1188 {
1189 Vector3 pos = VehiclePosition;
1190 pos.Z = m_VhoverTargetHeight;
1191 VehiclePosition = pos;
1192
1193 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos);
1194 }
1195 }
1196 else
1197 {
1198 // Error is positive if below the target and negative if above.
1199 Vector3 hpos = VehiclePosition;
1200 float verticalError = m_VhoverTargetHeight - hpos.Z;
1201 float verticalCorrection = verticalError / m_VhoverTimescale;
1202 verticalCorrection *= m_VhoverEfficiency;
1203
1204 hpos.Z += verticalCorrection;
1205 VehiclePosition = hpos;
1206
1207 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
1208 Vector3 vel = VehicleVelocity;
1209 vel.Z = 0f;
1210 VehicleVelocity = vel;
1211
1212 /*
1213 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
1214 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1215 verticalCorrection *= m_vehicleMass;
1216
1217 // TODO: implement m_VhoverEfficiency correctly
1218 VehicleAddForceImpulse(verticalCorrection);
1219 */
1220
1221 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
1222 ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency,
1223 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1224 verticalError, verticalCorrection);
1225 }
1226 }
1227 }
1228
1229 public bool ComputeLinearBlockingEndPoint(float pTimestep)
1230 {
1231 bool changed = false;
1232
1233 Vector3 pos = VehiclePosition;
1234 Vector3 posChange = pos - m_lastPositionVector;
1235 if (m_BlockingEndPoint != Vector3.Zero)
1236 {
1237 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
1238 {
1239 pos.X -= posChange.X + 1;
1240 changed = true;
1241 }
1242 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
1243 {
1244 pos.Y -= posChange.Y + 1;
1245 changed = true;
1246 }
1247 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
1248 {
1249 pos.Z -= posChange.Z + 1;
1250 changed = true;
1251 }
1252 if (pos.X <= 0)
1253 {
1254 pos.X += posChange.X + 1;
1255 changed = true;
1256 }
1257 if (pos.Y <= 0)
1258 {
1259 pos.Y += posChange.Y + 1;
1260 changed = true;
1261 }
1262 if (changed)
1263 {
1264 VehiclePosition = pos;
1265 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1266 ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos);
1267 }
1268 }
1269 return changed;
1270 }
1271
1272 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1273 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
1274 // used with conjunction with banking: the strength of the banking will decay when the
1275 // vehicle no longer experiences collisions. The decay timescale is the same as
1276 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1277 // when they are in mid jump.
1278 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1279 // This is just using the ground and a general collision check. Should really be using
1280 // a downward raycast to find what is below.
1281 public void ComputeLinearMotorUp(float pTimestep)
1282 {
1283 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1284 {
1285 // This code tries to decide if the object is not on the ground and then pushing down
1286 /*
1287 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1288 distanceAboveGround = VehiclePosition.Z - targetHeight;
1289 // Not colliding if the vehicle is off the ground
1290 if (!Prim.HasSomeCollision)
1291 {
1292 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1293 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
1294 }
1295 // TODO: this calculation is wrong. From the description at
1296 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1297 // has a decay factor. This says this force should
1298 // be computed with a motor.
1299 // TODO: add interaction with banking.
1300 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1301 Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret);
1302 */
1303
1304 // Another approach is to measure if we're going up. If going up and not colliding,
1305 // the vehicle is in the air. Fix that by pushing down.
1306 if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1)
1307 {
1308 // Get rid of any of the velocity vector that is pushing us up.
1309 float upVelocity = VehicleVelocity.Z;
1310 VehicleVelocity += new Vector3(0, 0, -upVelocity);
1311
1312 /*
1313 // If we're pointed up into the air, we should nose down
1314 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1315 // The rotation around the Y axis is pitch up or down
1316 if (pointingDirection.Y > 0.01f)
1317 {
1318 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
1319 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
1320 // Rotate into world coordinates and apply to vehicle
1321 angularCorrectionVector *= VehicleOrientation;
1322 VehicleAddAngularForce(angularCorrectionVector);
1323 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
1324 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
1325 }
1326 */
1327 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1328 ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity);
1329 }
1330 }
1331 }
1332
1333 private void ApplyGravity(float pTimeStep)
1334 {
1335 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1336
1337 // Hack to reduce downward force if the vehicle is probably sitting on the ground
1338 if (ControllingPrim.HasSomeCollision && IsGroundVehicle)
1339 appliedGravity *= BSParam.VehicleGroundGravityFudge;
1340
1341 VehicleAddForce(appliedGravity);
1342
1343 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
1344 ControllingPrim.LocalID, m_VehicleGravity,
1345 ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1346 }
1347
1348 // =======================================================================
1349 // =======================================================================
1350 // Apply the effect of the angular motor.
1351 // The 'contribution' is how much angular correction velocity each function wants.
1352 // All the contributions are added together and the resulting velocity is
1353 // set directly on the vehicle.
1354 private void MoveAngular(float pTimestep)
1355 {
1356 ComputeAngularTurning(pTimestep);
1357
1358 ComputeAngularVerticalAttraction();
1359
1360 ComputeAngularDeflection();
1361
1362 ComputeAngularBanking();
1363
1364 // ==================================================================
1365 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f))
1366 {
1367 // The vehicle is not adding anything angular wise.
1368 VehicleRotationalVelocity = Vector3.Zero;
1369 VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID);
1370 }
1371 else
1372 {
1373 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity);
1374 }
1375
1376 // ==================================================================
1377 //Offset section
1378 if (m_linearMotorOffset != Vector3.Zero)
1379 {
1380 //Offset of linear velocity doesn't change the linear velocity,
1381 // but causes a torque to be applied, for example...
1382 //
1383 // IIIII >>> IIIII
1384 // IIIII >>> IIIII
1385 // IIIII >>> IIIII
1386 // ^
1387 // | Applying a force at the arrow will cause the object to move forward, but also rotate
1388 //
1389 //
1390 // The torque created is the linear velocity crossed with the offset
1391
1392 // TODO: this computation should be in the linear section
1393 // because that is where we know the impulse being applied.
1394 Vector3 torqueFromOffset = Vector3.Zero;
1395 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
1396 if (float.IsNaN(torqueFromOffset.X))
1397 torqueFromOffset.X = 0;
1398 if (float.IsNaN(torqueFromOffset.Y))
1399 torqueFromOffset.Y = 0;
1400 if (float.IsNaN(torqueFromOffset.Z))
1401 torqueFromOffset.Z = 0;
1402
1403 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1404 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset);
1405 }
1406
1407 }
1408
1409 private void ComputeAngularTurning(float pTimestep)
1410 {
1411 // The user wants this many radians per second angular change?
1412 Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG
1413 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleFrameOrientation);
1414 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1415
1416 // ==================================================================
1417 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1418 // This flag prevents linear deflection parallel to world z-axis. This is useful
1419 // for preventing ground vehicles with large linear deflection, like bumper cars,
1420 // from climbing their linear deflection into the sky.
1421 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1422 // TODO: This is here because this is where ODE put it but documentation says it
1423 // is a linear effect. Where should this check go?
1424 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1425 // {
1426 // angularMotorContributionV.X = 0f;
1427 // angularMotorContributionV.Y = 0f;
1428 // }
1429
1430 // Reduce any velocity by friction.
1431 Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
1432 angularMotorContributionV -= (currentAngularV * frictionFactorW);
1433
1434 Vector3 angularMotorContributionW = angularMotorContributionV * VehicleFrameOrientation;
1435 VehicleRotationalVelocity += angularMotorContributionW;
1436
1437 VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}",
1438 ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW);
1439 }
1440
1441 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1442 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1443 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1444 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1445 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1446 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1447 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1448 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1449 public void ComputeAngularVerticalAttraction()
1450 {
1451
1452 // If vertical attaction timescale is reasonable
1453 if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1454 {
1455 Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleFrameOrientation;
1456 switch (BSParam.VehicleAngularVerticalAttractionAlgorithm)
1457 {
1458 case 0:
1459 {
1460 //Another formula to try got from :
1461 //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
1462
1463 // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
1464 // since only computing half the distance between the angles.
1465 float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
1466
1467 // Make a prediction of where the up axis will be when this is applied rather then where it is now as
1468 // this makes for a smoother adjustment and less fighting between the various forces.
1469 Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1470
1471 // This is only half the distance to the target so it will take 2 seconds to complete the turn.
1472 Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
1473
1474 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != 0)
1475 {
1476 Vector3 vehicleForwardAxis = Vector3.UnitX * VehicleFrameOrientation;
1477 torqueVector = ProjectVector(torqueVector, vehicleForwardAxis);
1478 }
1479
1480 // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
1481 Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed;
1482
1483 VehicleRotationalVelocity += vertContributionV;
1484
1485 VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}",
1486 ControllingPrim.LocalID,
1487 verticalAttractionSpeed,
1488 vehicleUpAxis,
1489 predictedUp,
1490 torqueVector,
1491 vertContributionV);
1492 break;
1493 }
1494 case 1:
1495 {
1496 // Possible solution derived from a discussion at:
1497 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1498
1499 // Create a rotation that is only the vehicle's rotation around Z
1500 Vector3 currentEulerW = Vector3.Zero;
1501 VehicleFrameOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z);
1502 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z);
1503
1504 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1505 Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleFrameOrientation);
1506 // Compute the angle between those to vectors.
1507 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation)));
1508 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1509
1510 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1511 // TODO: add 'efficiency'.
1512 // differenceAngle /= m_verticalAttractionTimescale;
1513
1514 // Create the quaterian representing the correction angle
1515 Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle);
1516
1517 // Turn that quaternion into Euler values to make it into velocities to apply.
1518 Vector3 vertContributionW = Vector3.Zero;
1519 correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z);
1520 vertContributionW *= -1f;
1521 vertContributionW /= m_verticalAttractionTimescale;
1522
1523 VehicleRotationalVelocity += vertContributionW;
1524
1525 VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}",
1526 ControllingPrim.LocalID,
1527 vehicleUpAxis,
1528 differenceAxisW,
1529 differenceAngle,
1530 correctionRotationW,
1531 vertContributionW);
1532 break;
1533 }
1534 case 2:
1535 {
1536 Vector3 vertContributionV = Vector3.Zero;
1537 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1538
1539 // Take a vector pointing up and convert it from world to vehicle relative coords.
1540 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation);
1541
1542 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1543 // is now:
1544 // leaning to one side: rotated around the X axis with the Y value going
1545 // from zero (nearly straight up) to one (completely to the side)) or
1546 // leaning front-to-back: rotated around the Y axis with the value of X being between
1547 // zero and one.
1548 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1549
1550 // Y error means needed rotation around X axis and visa versa.
1551 // Since the error goes from zero to one, the asin is the corresponding angle.
1552 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1553 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1554 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1555
1556 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1557 if (verticalError.Z < 0f)
1558 {
1559 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
1560 // vertContribution.Y -= PIOverFour;
1561 }
1562
1563 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1564 // Correction happens over a number of seconds.
1565 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1566
1567 // The correction happens over the user's time period
1568 vertContributionV /= m_verticalAttractionTimescale;
1569
1570 // Rotate the vehicle rotation to the world coordinates.
1571 VehicleRotationalVelocity += (vertContributionV * VehicleFrameOrientation);
1572
1573 VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}",
1574 ControllingPrim.LocalID,
1575 vehicleUpAxis,
1576 origRotVelW,
1577 verticalError,
1578 unscaledContribVerticalErrorV,
1579 m_verticalAttractionEfficiency,
1580 m_verticalAttractionTimescale,
1581 vertContributionV);
1582 break;
1583 }
1584 default:
1585 {
1586 break;
1587 }
1588 }
1589 }
1590 }
1591
1592 // Angular correction to correct the direction the vehicle is pointing to be
1593 // the direction is should want to be pointing.
1594 // The vehicle is moving in some direction and correct its orientation to it is pointing
1595 // in that direction.
1596 // TODO: implement reference frame.
1597 public void ComputeAngularDeflection()
1598 {
1599
1600 if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1601 {
1602 Vector3 deflectContributionV = Vector3.Zero;
1603
1604 // The direction the vehicle is moving
1605 Vector3 movingDirection = VehicleVelocity;
1606 movingDirection.Normalize();
1607
1608 // If the vehicle is going backward, it is still pointing forward
1609 movingDirection *= Math.Sign(VehicleForwardSpeed);
1610
1611 // The direction the vehicle is pointing
1612 Vector3 pointingDirection = Vector3.UnitX * VehicleFrameOrientation;
1613 //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep
1614 // from overshooting and allow this correction to merge with the Vertical Attraction peacefully.
1615 Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1616 predictedPointingDirection.Normalize();
1617
1618 // The difference between what is and what should be.
1619 // Vector3 deflectionError = movingDirection - predictedPointingDirection;
1620 Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection);
1621
1622 // Don't try to correct very large errors (not our job)
1623 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1624 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1625 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1626 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1627 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1628 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1629
1630 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1631
1632 // Scale the correction by recovery timescale and efficiency
1633 // Not modeling a spring so clamp the scale to no more then the arc
1634 deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f);
1635 //deflectContributionV /= m_angularDeflectionTimescale;
1636
1637 VehicleRotationalVelocity += deflectContributionV;
1638 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1639 ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1640 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}",
1641 ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection);
1642 }
1643 }
1644
1645 // Angular change to rotate the vehicle around the Z axis when the vehicle
1646 // is tipped around the X axis.
1647 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1648 // The vertical attractor feature must be enabled in order for the banking behavior to
1649 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1650 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1651 // of the yaw effect will be proportional to the
1652 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1653 // velocity along its preferred axis of motion.
1654 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1655 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1656 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1657 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1658 // Negating the banking coefficient will make it so that the vehicle leans to the
1659 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1660 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1661 // banking vehicles do what you want rather than what the laws of physics allow.
1662 // For example, consider a real motorcycle...it must be moving forward in order for
1663 // it to turn while banking, however video-game motorcycles are often configured
1664 // to turn in place when at a dead stop--because they are often easier to control
1665 // that way using the limited interface of the keyboard or game controller. The
1666 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1667 // banking by functioning as a slider between a banking that is correspondingly
1668 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1669 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1670 // to "dynamic" where the banking is also proportional to its velocity along its
1671 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1672 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1673 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1674 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1675 // make a sluggish vehicle by giving it a timescale of several seconds.
1676 public void ComputeAngularBanking()
1677 {
1678 if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1679 {
1680 Vector3 bankingContributionV = Vector3.Zero;
1681
1682 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1683 // As the vehicle rolls to the right or left, the Y value will increase from
1684 // zero (straight up) to 1 or -1 (full tilt right or left)
1685 Vector3 rollComponents = Vector3.UnitZ * VehicleFrameOrientation;
1686
1687 // Figure out the yaw value for this much roll.
1688 float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
1689 // actual error = static turn error + dynamic turn error
1690 float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
1691
1692 // TODO: the banking effect should not go to infinity but what to limit it to?
1693 // And what should happen when this is being added to a user defined yaw that is already PI*4?
1694 mixedYawAngle = ClampInRange(-FourPI, mixedYawAngle, FourPI);
1695
1696 // Build the force vector to change rotation from what it is to what it should be
1697 bankingContributionV.Z = -mixedYawAngle;
1698
1699 // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
1700 bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
1701
1702 VehicleRotationalVelocity += bankingContributionV;
1703
1704
1705 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1706 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1707 }
1708 }
1709
1710 // This is from previous instantiations of XXXDynamics.cs.
1711 // Applies roll reference frame.
1712 // TODO: is this the right way to separate the code to do this operation?
1713 // Should this be in MoveAngular()?
1714 internal void LimitRotation(float timestep)
1715 {
1716 Quaternion rotq = VehicleOrientation;
1717 Quaternion m_rot = rotq;
1718 if (m_RollreferenceFrame != Quaternion.Identity)
1719 {
1720 if (rotq.X >= m_RollreferenceFrame.X)
1721 {
1722 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
1723 }
1724 if (rotq.Y >= m_RollreferenceFrame.Y)
1725 {
1726 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
1727 }
1728 if (rotq.X <= -m_RollreferenceFrame.X)
1729 {
1730 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
1731 }
1732 if (rotq.Y <= -m_RollreferenceFrame.Y)
1733 {
1734 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
1735 }
1736 }
1737 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
1738 {
1739 m_rot.X = 0;
1740 m_rot.Y = 0;
1741 }
1742 if (rotq != m_rot)
1743 {
1744 VehicleOrientation = m_rot;
1745 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot);
1746 }
1747
1748 }
1749
1750 // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce
1751 // some value by to apply this friction.
1752 private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep)
1753 {
1754 Vector3 frictionFactor = Vector3.Zero;
1755 if (friction != BSMotor.InfiniteVector)
1756 {
1757 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
1758 // Individual friction components can be 'infinite' so compute each separately.
1759 frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X);
1760 frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y);
1761 frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z);
1762 frictionFactor *= pTimestep;
1763 }
1764 return frictionFactor;
1765 }
1766
1767 private float SortedClampInRange(float clampa, float val, float clampb)
1768 {
1769 if (clampa > clampb)
1770 {
1771 float temp = clampa;
1772 clampa = clampb;
1773 clampb = temp;
1774 }
1775 return ClampInRange(clampa, val, clampb);
1776
1777 }
1778
1779 //Given a Vector and a unit vector will return the amount of the vector is on the same axis as the unit.
1780 private Vector3 ProjectVector(Vector3 vector, Vector3 onNormal)
1781 {
1782 float vectorDot = Vector3.Dot(vector, onNormal);
1783 return onNormal * vectorDot;
1784
1785 }
1786
1787 private float ClampInRange(float low, float val, float high)
1788 {
1789 return Math.Max(low, Math.Min(val, high));
1790 // return Utils.Clamp(val, low, high);
1791 }
1792
1793 // Invoke the detailed logger and output something if it's enabled.
1794 private void VDetailLog(string msg, params Object[] args)
1795 {
1796 if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
1797 ControllingPrim.PhysScene.DetailLog(msg, args);
1798 }
1799 }
1800}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
new file mode 100755
index 0000000..87eba33
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
@@ -0,0 +1,503 @@
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 OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public abstract class BSLinkset
37{
38 // private static string LogHeader = "[BULLETSIM LINKSET]";
39
40 public enum LinksetImplementation
41 {
42 Constraint = 0, // linkset tied together with constraints
43 Compound = 1, // linkset tied together as a compound object
44 Manual = 2 // linkset tied together manually (code moves all the pieces)
45 }
46 // Create the correct type of linkset for this child
47 public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
48 {
49 BSLinkset ret = null;
50
51 switch (parent.LinksetType)
52 {
53 case LinksetImplementation.Constraint:
54 ret = new BSLinksetConstraints(physScene, parent);
55 break;
56 case LinksetImplementation.Compound:
57 ret = new BSLinksetCompound(physScene, parent);
58 break;
59 case LinksetImplementation.Manual:
60 // ret = new BSLinksetManual(physScene, parent);
61 break;
62 default:
63 ret = new BSLinksetCompound(physScene, parent);
64 break;
65 }
66 if (ret == null)
67 {
68 physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
69 }
70 return ret;
71 }
72
73 public class BSLinkInfo
74 {
75 public BSPrimLinkable member;
76 public BSLinkInfo(BSPrimLinkable pMember)
77 {
78 member = pMember;
79 }
80 public virtual void ResetLink() { }
81 public virtual void SetLinkParameters(BSConstraint constrain) { }
82 // Returns 'true' if physical property updates from the child should be reported to the simulator
83 public virtual bool ShouldUpdateChildProperties() { return false; }
84 }
85
86 public LinksetImplementation LinksetImpl { get; protected set; }
87
88 public BSPrimLinkable LinksetRoot { get; protected set; }
89
90 protected BSScene m_physicsScene { get; private set; }
91
92 static int m_nextLinksetID = 1;
93 public int LinksetID { get; private set; }
94
95 // The children under the root in this linkset.
96 // protected HashSet<BSPrimLinkable> m_children;
97 protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children;
98
99 // We lock the diddling of linkset classes to prevent any badness.
100 // This locks the modification of the instances of this class. Changes
101 // to the physical representation is done via the tainting mechenism.
102 protected object m_linksetActivityLock = new Object();
103
104 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
105 public float LinksetMass { get; protected set; }
106
107 public virtual bool LinksetIsColliding { get { return false; } }
108
109 public OMV.Vector3 CenterOfMass
110 {
111 get { return ComputeLinksetCenterOfMass(); }
112 }
113
114 public OMV.Vector3 GeometricCenter
115 {
116 get { return ComputeLinksetGeometricCenter(); }
117 }
118
119 protected BSLinkset(BSScene scene, BSPrimLinkable parent)
120 {
121 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++;
123 // We create LOTS of linksets.
124 if (m_nextLinksetID <= 0)
125 m_nextLinksetID = 1;
126 m_physicsScene = scene;
127 LinksetRoot = parent;
128 m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>();
129 LinksetMass = parent.RawMass;
130 Rebuilding = false;
131 RebuildScheduled = false;
132
133 parent.ClearDisplacement();
134 }
135
136 // Link to a linkset where the child knows the parent.
137 // Parent changing should not happen so do some sanity checking.
138 // We return the parent's linkset so the child can track its membership.
139 // Called at runtime.
140 public BSLinkset AddMeToLinkset(BSPrimLinkable child)
141 {
142 lock (m_linksetActivityLock)
143 {
144 // Don't add the root to its own linkset
145 if (!IsRoot(child))
146 AddChildToLinkset(child);
147 LinksetMass = ComputeLinksetMass();
148 }
149 return this;
150 }
151
152 // Remove a child from a linkset.
153 // Returns a new linkset for the child which is a linkset of one (just the
154 // orphened child).
155 // Called at runtime.
156 public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
157 {
158 lock (m_linksetActivityLock)
159 {
160 if (IsRoot(child))
161 {
162 // Cannot remove the root from a linkset.
163 return this;
164 }
165 RemoveChildFromLinkset(child, inTaintTime);
166 LinksetMass = ComputeLinksetMass();
167 }
168
169 // The child is down to a linkset of just itself
170 return BSLinkset.Factory(m_physicsScene, child);
171 }
172
173 // Return 'true' if the passed object is the root object of this linkset
174 public bool IsRoot(BSPrimLinkable requestor)
175 {
176 return (requestor.LocalID == LinksetRoot.LocalID);
177 }
178
179 public int NumberOfChildren { get { return m_children.Count; } }
180
181 // Return 'true' if this linkset has any children (more than the root member)
182 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
183
184 // Return 'true' if this child is in this linkset
185 public bool HasChild(BSPrimLinkable child)
186 {
187 bool ret = false;
188 lock (m_linksetActivityLock)
189 {
190 ret = m_children.ContainsKey(child);
191 }
192 return ret;
193 }
194
195 // Perform an action on each member of the linkset including root prim.
196 // Depends on the action on whether this should be done at taint time.
197 public delegate bool ForEachMemberAction(BSPrimLinkable obj);
198 public virtual bool ForEachMember(ForEachMemberAction action)
199 {
200 bool ret = false;
201 lock (m_linksetActivityLock)
202 {
203 action(LinksetRoot);
204 foreach (BSPrimLinkable po in m_children.Keys)
205 {
206 if (action(po))
207 break;
208 }
209 }
210 return ret;
211 }
212
213 public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
214 {
215 bool ret = false;
216 BSLinkInfo found = null;
217 lock (m_linksetActivityLock)
218 {
219 ret = m_children.TryGetValue(child, out found);
220 }
221 foundInfo = found;
222 return ret;
223 }
224 // Perform an action on each member of the linkset including root prim.
225 // Depends on the action on whether this should be done at taint time.
226 public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
227 public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
228 {
229 bool ret = false;
230 lock (m_linksetActivityLock)
231 {
232 foreach (BSLinkInfo po in m_children.Values)
233 {
234 if (action(po))
235 break;
236 }
237 }
238 return ret;
239 }
240
241 // Check the type of the link and return 'true' if the link is flexible and the
242 // updates from the child should be sent to the simulator so things change.
243 public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
244 {
245 bool ret = false;
246
247 BSLinkInfo linkInfo;
248 if (m_children.TryGetValue(child, out linkInfo))
249 {
250 ret = linkInfo.ShouldUpdateChildProperties();
251 }
252
253 return ret;
254 }
255
256 // Called after a simulation step to post a collision with this object.
257 // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
258 // anything to add for the collision and it should be passed through normal processing.
259 // Default processing for a linkset.
260 public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee,
261 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
262 {
263 bool ret = false;
264
265 // prims in the same linkset cannot collide with each other
266 BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
267 if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
268 {
269 // By returning 'true', we tell the caller the collision has been 'handled' so it won't
270 // do anything about this collision and thus, effectivily, ignoring the collision.
271 ret = true;
272 }
273 else
274 {
275 // Not a collision between members of the linkset. Must be a real collision.
276 // So the linkset root can know if there is a collision anywhere in the linkset.
277 LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
278 }
279
280 return ret;
281 }
282
283 // I am the root of a linkset and a new child is being added
284 // Called while LinkActivity is locked.
285 protected abstract void AddChildToLinkset(BSPrimLinkable child);
286
287 // I am the root of a linkset and one of my children is being removed.
288 // Safe to call even if the child is not really in my linkset.
289 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime);
290
291 // When physical properties are changed the linkset needs to recalculate
292 // its internal properties.
293 // May be called at runtime or taint-time.
294 public virtual void Refresh(BSPrimLinkable requestor)
295 {
296 LinksetMass = ComputeLinksetMass();
297 }
298
299 // Flag denoting the linkset is in the process of being rebuilt.
300 // Used to know not the schedule a rebuild in the middle of a rebuild.
301 // Because of potential update calls that could want to schedule another rebuild.
302 protected bool Rebuilding { get; set; }
303
304 // Flag saying a linkset rebuild has been scheduled.
305 // This is turned on when the rebuild is requested and turned off when
306 // the rebuild is complete. Used to limit modifications to the
307 // linkset parameters while the linkset is in an intermediate state.
308 // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object
309 public bool RebuildScheduled { get; protected set; }
310
311 // The object is going dynamic (physical). Do any setup necessary
312 // for a dynamic linkset.
313 // Only the state of the passed object can be modified. The rest of the linkset
314 // has not yet been fully constructed.
315 // Return 'true' if any properties updated on the passed object.
316 // Called at taint-time!
317 public abstract bool MakeDynamic(BSPrimLinkable child);
318
319 public virtual bool AllPartsComplete
320 {
321 get {
322 bool ret = true;
323 this.ForEachMember((member) =>
324 {
325 if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting)
326 {
327 ret = false;
328 return true; // exit loop
329 }
330 return false; // continue loop
331 });
332 return ret;
333 }
334 }
335
336 // The object is going static (non-physical). Do any setup necessary
337 // for a static linkset.
338 // Return 'true' if any properties updated on the passed object.
339 // Called at taint-time!
340 public abstract bool MakeStatic(BSPrimLinkable child);
341
342 // Called when a parameter update comes from the physics engine for any object
343 // of the linkset is received.
344 // Passed flag is update came from physics engine (true) or the user (false).
345 // Called at taint-time!!
346 public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
347
348 // Routine used when rebuilding the body of the root of the linkset
349 // Destroy all the constraints have have been made to root.
350 // This is called when the root body is changing.
351 // Returns 'true' of something was actually removed and would need restoring
352 // Called at taint-time!!
353 public abstract bool RemoveDependencies(BSPrimLinkable child);
354
355 // ================================================================
356 // Some physical setting happen to all members of the linkset
357 public virtual void SetPhysicalFriction(float friction)
358 {
359 ForEachMember((member) =>
360 {
361 if (member.PhysBody.HasPhysicalBody)
362 m_physicsScene.PE.SetFriction(member.PhysBody, friction);
363 return false; // 'false' says to continue looping
364 }
365 );
366 }
367 public virtual void SetPhysicalRestitution(float restitution)
368 {
369 ForEachMember((member) =>
370 {
371 if (member.PhysBody.HasPhysicalBody)
372 m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
373 return false; // 'false' says to continue looping
374 }
375 );
376 }
377 public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
378 {
379 ForEachMember((member) =>
380 {
381 if (member.PhysBody.HasPhysicalBody)
382 m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
383 return false; // 'false' says to continue looping
384 }
385 );
386 }
387 public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
388 {
389 ForEachMember((member) =>
390 {
391 if (member.PhysBody.HasPhysicalBody)
392 {
393 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
394 member.Inertia = inertia * inertiaFactor;
395 m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
396 m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
397 DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
398
399 }
400 return false; // 'false' says to continue looping
401 }
402 );
403 }
404 public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
405 {
406 ForEachMember((member) =>
407 {
408 if (member.PhysBody.HasPhysicalBody)
409 m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
410 return false; // 'false' says to continue looping
411 }
412 );
413 }
414 public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
415 {
416 ForEachMember((member) =>
417 {
418 if (member.PhysBody.HasPhysicalBody)
419 m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
420 return false; // 'false' says to continue looping
421 }
422 );
423 }
424 public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
425 {
426 ForEachMember((member) =>
427 {
428 if (member.PhysBody.HasPhysicalBody)
429 m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
430 return false; // 'false' says to continue looping
431 }
432 );
433 }
434 // ================================================================
435 protected virtual float ComputeLinksetMass()
436 {
437 float mass = LinksetRoot.RawMass;
438 if (HasAnyChildren)
439 {
440 lock (m_linksetActivityLock)
441 {
442 foreach (BSPrimLinkable bp in m_children.Keys)
443 {
444 mass += bp.RawMass;
445 }
446 }
447 }
448 return mass;
449 }
450
451 // Computes linkset's center of mass in world coordinates.
452 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
453 {
454 OMV.Vector3 com;
455 lock (m_linksetActivityLock)
456 {
457 com = LinksetRoot.Position * LinksetRoot.RawMass;
458 float totalMass = LinksetRoot.RawMass;
459
460 foreach (BSPrimLinkable bp in m_children.Keys)
461 {
462 com += bp.Position * bp.RawMass;
463 totalMass += bp.RawMass;
464 }
465 if (totalMass != 0f)
466 com /= totalMass;
467 }
468
469 return com;
470 }
471
472 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
473 {
474 OMV.Vector3 com;
475 lock (m_linksetActivityLock)
476 {
477 com = LinksetRoot.Position;
478
479 foreach (BSPrimLinkable bp in m_children.Keys)
480 {
481 com += bp.Position;
482 }
483 com /= (m_children.Count + 1);
484 }
485
486 return com;
487 }
488
489 #region Extension
490 public virtual object Extension(string pFunct, params object[] pParams)
491 {
492 return null;
493 }
494 #endregion // Extension
495
496 // Invoke the detailed logger and output something if it's enabled.
497 protected void DetailLog(string msg, params Object[] args)
498 {
499 if (m_physicsScene.PhysicsLogging.Enabled)
500 m_physicsScene.DetailLog(msg, args);
501 }
502}
503}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
new file mode 100755
index 0000000..cae9efa
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
@@ -0,0 +1,477 @@
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.Framework;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37
38public sealed class BSLinksetCompound : BSLinkset
39{
40#pragma warning disable 414
41 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
42#pragma warning restore 414
43
44 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
45 : base(scene, parent)
46 {
47 LinksetImpl = LinksetImplementation.Compound;
48 }
49
50 // ================================================================
51 // Changing the physical property of the linkset only needs to change the root
52 public override void SetPhysicalFriction(float friction)
53 {
54 if (LinksetRoot.PhysBody.HasPhysicalBody)
55 m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
56 }
57 public override void SetPhysicalRestitution(float restitution)
58 {
59 if (LinksetRoot.PhysBody.HasPhysicalBody)
60 m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
61 }
62 public override void SetPhysicalGravity(OMV.Vector3 gravity)
63 {
64 if (LinksetRoot.PhysBody.HasPhysicalBody)
65 m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
66 }
67 public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
68 {
69 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
70 LinksetRoot.Inertia = inertia * inertiaFactor;
71 m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
72 m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
73 }
74 public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
75 {
76 if (LinksetRoot.PhysBody.HasPhysicalBody)
77 m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
78 }
79 public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
80 {
81 if (LinksetRoot.PhysBody.HasPhysicalBody)
82 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
83 }
84 public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
85 {
86 if (LinksetRoot.PhysBody.HasPhysicalBody)
87 m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
88 }
89 // ================================================================
90
91 // When physical properties are changed the linkset needs to recalculate
92 // its internal properties.
93 public override void Refresh(BSPrimLinkable requestor)
94 {
95 // Something changed so do the rebuilding thing
96 ScheduleRebuild(requestor);
97 base.Refresh(requestor);
98 }
99
100 // Schedule a refresh to happen after all the other taint processing.
101 private void ScheduleRebuild(BSPrimLinkable requestor)
102 {
103 // When rebuilding, it is possible to set properties that would normally require a rebuild.
104 // If already rebuilding, don't request another rebuild.
105 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
106 lock (m_linksetActivityLock)
107 {
108 if (!RebuildScheduled && !Rebuilding && HasAnyChildren)
109 {
110 InternalScheduleRebuild(requestor);
111 }
112 }
113 }
114
115 // Must be called with m_linksetActivityLock or race conditions will haunt you.
116 private void InternalScheduleRebuild(BSPrimLinkable requestor)
117 {
118 DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}",
119 requestor.LocalID, Rebuilding, HasAnyChildren);
120 RebuildScheduled = true;
121 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
122 {
123 if (HasAnyChildren)
124 {
125 if (this.AllPartsComplete)
126 {
127 RecomputeLinksetCompound();
128 }
129 else
130 {
131 DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete",
132 requestor.LocalID);
133 InternalScheduleRebuild(requestor);
134 }
135 }
136 RebuildScheduled = false;
137 });
138 }
139
140 // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
141 // Only the state of the passed object can be modified. The rest of the linkset
142 // has not yet been fully constructed.
143 // Return 'true' if any properties updated on the passed object.
144 // Called at taint-time!
145 public override bool MakeDynamic(BSPrimLinkable child)
146 {
147 bool ret = false;
148 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
149 if (IsRoot(child))
150 {
151 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
152 Refresh(LinksetRoot);
153 }
154 return ret;
155 }
156
157 // The object is going static (non-physical). We do not do anything for static linksets.
158 // Return 'true' if any properties updated on the passed object.
159 // Called at taint-time!
160 public override bool MakeStatic(BSPrimLinkable child)
161 {
162 bool ret = false;
163
164 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
165 child.ClearDisplacement();
166 if (IsRoot(child))
167 {
168 // Schedule a rebuild to verify that the root shape is set to the real shape.
169 Refresh(LinksetRoot);
170 }
171 return ret;
172 }
173
174 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
175 // Called at taint-time.
176 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
177 {
178 if (!LinksetRoot.IsPhysicallyActive)
179 {
180 // No reason to do this physical stuff for static linksets.
181 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
182 return;
183 }
184
185 // The user moving a child around requires the rebuilding of the linkset compound shape
186 // One problem is this happens when a border is crossed -- the simulator implementation
187 // stores the position into the group which causes the move of the object
188 // but it also means all the child positions get updated.
189 // What would cause an unnecessary rebuild so we make sure the linkset is in a
190 // region before bothering to do a rebuild.
191 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
192 {
193 // If a child of the linkset is updating only the position or rotation, that can be done
194 // without rebuilding the linkset.
195 // If a handle for the child can be fetch, we update the child here. If a rebuild was
196 // scheduled by someone else, the rebuild will just replace this setting.
197
198 bool updatedChild = false;
199 // Anything other than updating position or orientation usually means a physical update
200 // and that is caused by us updating the object.
201 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
202 {
203 // Find the physical instance of the child
204 if (!RebuildScheduled // if rebuilding, let the rebuild do it
205 && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change
206 && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned
207 && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
208 {
209 // It is possible that the linkset is still under construction and the child is not yet
210 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
211 // build the whole thing with the new position or rotation.
212 // The index must be checked because Bullet references the child array but does no validity
213 // checking of the child index passed.
214 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
215 if (updated.LinksetChildIndex < numLinksetChildren)
216 {
217 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
218 if (linksetChildShape.HasPhysicalShape)
219 {
220 // Found the child shape within the compound shape
221 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
222 updated.RawPosition - LinksetRoot.RawPosition,
223 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
224 true /* shouldRecalculateLocalAabb */);
225 updatedChild = true;
226 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
227 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
228 }
229 else // DEBUG DEBUG
230 { // DEBUG DEBUG
231 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
232 updated.LocalID, linksetChildShape);
233 } // DEBUG DEBUG
234 }
235 else // DEBUG DEBUG
236 { // DEBUG DEBUG
237 // the child is not yet in the compound shape. This is non-fatal.
238 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
239 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
240 } // DEBUG DEBUG
241 }
242 else // DEBUG DEBUG
243 { // DEBUG DEBUG
244 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
245 } // DEBUG DEBUG
246
247 if (!updatedChild)
248 {
249 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
250 // Note: there are several ways through this code that will not update the child if
251 // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
252 // there will already be a rebuild scheduled.
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
254 updated.LocalID, whichUpdated);
255 Refresh(updated);
256 }
257 }
258 }
259 }
260
261 // Routine called when rebuilding the body of some member of the linkset.
262 // If one of the bodies is being changed, the linkset needs rebuilding.
263 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
264 // Returns 'true' of something was actually removed and would need restoring
265 // Called at taint-time!!
266 public override bool RemoveDependencies(BSPrimLinkable child)
267 {
268 bool ret = false;
269
270 DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
271 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
272
273 Refresh(child);
274
275 return ret;
276 }
277
278 // ================================================================
279
280 // Add a new child to the linkset.
281 // Called while LinkActivity is locked.
282 protected override void AddChildToLinkset(BSPrimLinkable child)
283 {
284 if (!HasChild(child))
285 {
286 m_children.Add(child, new BSLinkInfo(child));
287
288 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
289
290 // Rebuild the compound shape with the new child shape included
291 Refresh(child);
292 }
293 return;
294 }
295
296 // Remove the specified child from the linkset.
297 // Safe to call even if the child is not really in the linkset.
298 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
299 {
300 child.ClearDisplacement();
301
302 if (m_children.Remove(child))
303 {
304 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
305 child.LocalID,
306 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
307 child.LocalID, child.PhysBody.AddrString);
308
309 // Cause the child's body to be rebuilt and thus restored to normal operation
310 child.ForceBodyShapeRebuild(inTaintTime);
311
312 if (!HasAnyChildren)
313 {
314 // The linkset is now empty. The root needs rebuilding.
315 LinksetRoot.ForceBodyShapeRebuild(inTaintTime);
316 }
317 else
318 {
319 // Rebuild the compound shape with the child removed
320 Refresh(LinksetRoot);
321 }
322 }
323 return;
324 }
325
326 // Called before the simulation step to make sure the compound based linkset
327 // is all initialized.
328 // Constraint linksets are rebuilt every time.
329 // Note that this works for rebuilding just the root after a linkset is taken apart.
330 // Called at taint time!!
331 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
332 private void RecomputeLinksetCompound()
333 {
334 try
335 {
336 Rebuilding = true;
337
338 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
339 // to what they should be as if the root was not in a linkset.
340 // Not that bad since we only get into this routine if there are children in the linkset and
341 // something has been updated/changed.
342 // Have to do the rebuild before checking for physical because this might be a linkset
343 // being destructed and going non-physical.
344 LinksetRoot.ForceBodyShapeRebuild(true);
345
346 // There is no reason to build all this physical stuff for a non-physical or empty linkset.
347 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
348 {
349 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
350 return; // Note the 'finally' clause at the botton which will get executed.
351 }
352
353 // Get a new compound shape to build the linkset shape in.
354 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
355
356 // Compute a displacement for each component so it is relative to the center-of-mass.
357 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
358 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
359
360 OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
361 OMV.Vector3 origRootPosition = LinksetRoot.RawPosition;
362
363 // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass
364 OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
365 if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass)
366 {
367 // Zero everything if center-of-mass displacement is not being done.
368 centerDisplacementV = OMV.Vector3.Zero;
369 LinksetRoot.ClearDisplacement();
370 }
371 else
372 {
373 // The actual center-of-mass could have been set by the user.
374 centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
375 }
376
377 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
378 LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV);
379
380 // Add the shapes of all the components of the linkset
381 int memberIndex = 1;
382 ForEachMember((cPrim) =>
383 {
384 if (IsRoot(cPrim))
385 {
386 // Root shape is always index zero.
387 cPrim.LinksetChildIndex = 0;
388 }
389 else
390 {
391 cPrim.LinksetChildIndex = memberIndex;
392 memberIndex++;
393 }
394
395 // Get a reference to the shape of the child for adding of that shape to the linkset compound shape
396 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
397
398 // Offset the child shape from the center-of-mass and rotate it to root relative.
399 OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV;
400 OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
401
402 // Add the child shape to the compound shape being built
403 if (childShape.physShapeInfo.HasPhysicalShape)
404 {
405 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
406 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
407 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
408
409 // Since we are borrowing the shape of the child, disable the origional child body
410 if (!IsRoot(cPrim))
411 {
412 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
413 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
414 // We don't want collisions from the old linkset children.
415 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
416 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
417 }
418 }
419 else
420 {
421 // The linkset must be in an intermediate state where all the children have not yet
422 // been constructed. This sometimes happens on startup when everything is getting
423 // built and some shapes have to wait for assets to be read in.
424 // Just skip this linkset for the moment and cause the shape to be rebuilt next tick.
425 // One problem might be that the shape is broken somehow and it never becomes completely
426 // available. This might cause the rebuild to happen over and over.
427 InternalScheduleRebuild(LinksetRoot);
428 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}",
429 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
430 // Output an annoying warning. It should only happen once but if it keeps coming out,
431 // the user knows there is something wrong and will report it.
432 m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader);
433 m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}",
434 LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape);
435
436 // This causes the loop to bail on building the rest of this linkset.
437 // The rebuild operation will fix it up next tick or declare the object unbuildable.
438 return true;
439 }
440
441 return false; // 'false' says to move onto the next child in the list
442 });
443
444 // Replace the root shape with the built compound shape.
445 // Object removed and added to world to get collision cache rebuilt for new shape.
446 LinksetRoot.PhysShape.Dereference(m_physicsScene);
447 LinksetRoot.PhysShape = linksetShape;
448 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
449 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
450 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
451 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
452 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
453
454 // With all of the linkset packed into the root prim, it has the mass of everyone.
455 LinksetMass = ComputeLinksetMass();
456 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
457
458 if (UseBulletSimRootOffsetHack)
459 {
460 // Enable the physical position updator to return the position and rotation of the root shape.
461 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
462 // compound shape. This aleviates the need to offset the returned physical position by the
463 // center-of-mass offset.
464 // TODO: either debug this feature or remove it.
465 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
466 }
467 }
468 finally
469 {
470 Rebuilding = false;
471 }
472
473 // See that the Aabb surrounds the new shape
474 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
475 }
476}
477} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
new file mode 100755
index 0000000..4384cdc
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
@@ -0,0 +1,854 @@
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.OptionalModules.Scripting;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public sealed class BSLinksetConstraints : BSLinkset
38{
39 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
40
41 public class BSLinkInfoConstraint : BSLinkInfo
42 {
43 public ConstraintType constraintType;
44 public BSConstraint constraint;
45 public OMV.Vector3 linearLimitLow;
46 public OMV.Vector3 linearLimitHigh;
47 public OMV.Vector3 angularLimitLow;
48 public OMV.Vector3 angularLimitHigh;
49 public bool useFrameOffset;
50 public bool enableTransMotor;
51 public float transMotorMaxVel;
52 public float transMotorMaxForce;
53 public float cfm;
54 public float erp;
55 public float solverIterations;
56 //
57 public OMV.Vector3 frameInAloc;
58 public OMV.Quaternion frameInArot;
59 public OMV.Vector3 frameInBloc;
60 public OMV.Quaternion frameInBrot;
61 public bool useLinearReferenceFrameA;
62 // Spring
63 public bool[] springAxisEnable;
64 public float[] springDamping;
65 public float[] springStiffness;
66 public OMV.Vector3 springLinearEquilibriumPoint;
67 public OMV.Vector3 springAngularEquilibriumPoint;
68
69 public BSLinkInfoConstraint(BSPrimLinkable pMember)
70 : base(pMember)
71 {
72 constraint = null;
73 ResetLink();
74 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID);
75 }
76
77 // Set all the parameters for this constraint to a fixed, non-movable constraint.
78 public override void ResetLink()
79 {
80 // constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
81 constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE;
82 linearLimitLow = OMV.Vector3.Zero;
83 linearLimitHigh = OMV.Vector3.Zero;
84 angularLimitLow = OMV.Vector3.Zero;
85 angularLimitHigh = OMV.Vector3.Zero;
86 useFrameOffset = BSParam.LinkConstraintUseFrameOffset;
87 enableTransMotor = BSParam.LinkConstraintEnableTransMotor;
88 transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
89 transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
90 cfm = BSParam.LinkConstraintCFM;
91 erp = BSParam.LinkConstraintERP;
92 solverIterations = BSParam.LinkConstraintSolverIterations;
93 frameInAloc = OMV.Vector3.Zero;
94 frameInArot = OMV.Quaternion.Identity;
95 frameInBloc = OMV.Vector3.Zero;
96 frameInBrot = OMV.Quaternion.Identity;
97 useLinearReferenceFrameA = true;
98 springAxisEnable = new bool[6];
99 springDamping = new float[6];
100 springStiffness = new float[6];
101 for (int ii = 0; ii < springAxisEnable.Length; ii++)
102 {
103 springAxisEnable[ii] = false;
104 springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
105 springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
106 }
107 springLinearEquilibriumPoint = OMV.Vector3.Zero;
108 springAngularEquilibriumPoint = OMV.Vector3.Zero;
109 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID);
110 }
111
112 // Given a constraint, apply the current constraint parameters to same.
113 public override void SetLinkParameters(BSConstraint constrain)
114 {
115 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType);
116 switch (constraintType)
117 {
118 case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
119 case ConstraintType.D6_CONSTRAINT_TYPE:
120 BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
121 if (constrain6dof != null)
122 {
123 // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code.
124 // zero linear and angular limits makes the objects unable to move in relation to each other
125 constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
126 constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
127
128 // tweek the constraint to increase stability
129 constrain6dof.UseFrameOffset(useFrameOffset);
130 constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
131 constrain6dof.SetCFMAndERP(cfm, erp);
132 if (solverIterations != 0f)
133 {
134 constrain6dof.SetSolverIterations(solverIterations);
135 }
136 }
137 break;
138 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
139 BSConstraintSpring constrainSpring = constrain as BSConstraintSpring;
140 if (constrainSpring != null)
141 {
142 // zero linear and angular limits makes the objects unable to move in relation to each other
143 constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh);
144 constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh);
145
146 // tweek the constraint to increase stability
147 constrainSpring.UseFrameOffset(useFrameOffset);
148 constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
149 constrainSpring.SetCFMAndERP(cfm, erp);
150 if (solverIterations != 0f)
151 {
152 constrainSpring.SetSolverIterations(solverIterations);
153 }
154 for (int ii = 0; ii < springAxisEnable.Length; ii++)
155 {
156 constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]);
157 if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
158 constrainSpring.SetDamping(ii, springDamping[ii]);
159 if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
160 constrainSpring.SetStiffness(ii, springStiffness[ii]);
161 }
162 constrainSpring.CalculateTransforms();
163
164 if (springLinearEquilibriumPoint != OMV.Vector3.Zero)
165 constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint);
166 else
167 constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED);
168 }
169 break;
170 default:
171 break;
172 }
173 }
174
175 // Return 'true' if the property updates from the physics engine should be reported
176 // to the simulator.
177 // If the constraint is fixed, we don't need to report as the simulator and viewer will
178 // report the right things.
179 public override bool ShouldUpdateChildProperties()
180 {
181 bool ret = true;
182 if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE)
183 ret = false;
184
185 return ret;
186 }
187 }
188
189 public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
190 {
191 LinksetImpl = LinksetImplementation.Constraint;
192 }
193
194 private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]";
195
196 // When physical properties are changed the linkset needs to recalculate
197 // its internal properties.
198 // This is queued in the 'post taint' queue so the
199 // refresh will happen once after all the other taints are applied.
200 public override void Refresh(BSPrimLinkable requestor)
201 {
202 ScheduleRebuild(requestor);
203 base.Refresh(requestor);
204
205 }
206
207 private void ScheduleRebuild(BSPrimLinkable requestor)
208 {
209 DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
210 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
211
212 // When rebuilding, it is possible to set properties that would normally require a rebuild.
213 // If already rebuilding, don't request another rebuild.
214 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
215 lock (this)
216 {
217 if (!RebuildScheduled)
218 {
219 if (!Rebuilding && HasAnyChildren)
220 {
221 RebuildScheduled = true;
222 // Queue to happen after all the other taint processing
223 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
224 {
225 if (HasAnyChildren)
226 {
227 // Constraints that have not been changed are not rebuild but make sure
228 // the constraint of the requestor is rebuilt.
229 PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor);
230 // Rebuild the linkset and all its constraints.
231 RecomputeLinksetConstraints();
232 }
233 RebuildScheduled = false;
234 });
235 }
236 }
237 }
238 }
239
240 // The object is going dynamic (physical). Do any setup necessary
241 // for a dynamic linkset.
242 // Only the state of the passed object can be modified. The rest of the linkset
243 // has not yet been fully constructed.
244 // Return 'true' if any properties updated on the passed object.
245 // Called at taint-time!
246 public override bool MakeDynamic(BSPrimLinkable child)
247 {
248 bool ret = false;
249 DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
250 if (IsRoot(child))
251 {
252 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
253 Refresh(LinksetRoot);
254 }
255 return ret;
256 }
257
258 // The object is going static (non-physical). Do any setup necessary for a static linkset.
259 // Return 'true' if any properties updated on the passed object.
260 // This doesn't normally happen -- OpenSim removes the objects from the physical
261 // world if it is a static linkset.
262 // Called at taint-time!
263 public override bool MakeStatic(BSPrimLinkable child)
264 {
265 bool ret = false;
266
267 DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
268 child.ClearDisplacement();
269 if (IsRoot(child))
270 {
271 // Schedule a rebuild to verify that the root shape is set to the real shape.
272 Refresh(LinksetRoot);
273 }
274 return ret;
275 }
276
277 // Called at taint-time!!
278 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
279 {
280 // Nothing to do for constraints on property updates
281 }
282
283 // Routine called when rebuilding the body of some member of the linkset.
284 // Destroy all the constraints have have been made to root and set
285 // up to rebuild the constraints before the next simulation step.
286 // Returns 'true' of something was actually removed and would need restoring
287 // Called at taint-time!!
288 public override bool RemoveDependencies(BSPrimLinkable child)
289 {
290 bool ret = false;
291
292 DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
293 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
294
295 lock (m_linksetActivityLock)
296 {
297 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
298 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
299 // Cause the constraints, et al to be rebuilt before the next simulation step.
300 Refresh(LinksetRoot);
301 }
302 return ret;
303 }
304
305 // ================================================================
306
307 // Add a new child to the linkset.
308 // Called while LinkActivity is locked.
309 protected override void AddChildToLinkset(BSPrimLinkable child)
310 {
311 if (!HasChild(child))
312 {
313 m_children.Add(child, new BSLinkInfoConstraint(child));
314
315 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
316
317 // Cause constraints and assorted properties to be recomputed before the next simulation step.
318 Refresh(LinksetRoot);
319 }
320 return;
321 }
322
323 // Remove the specified child from the linkset.
324 // Safe to call even if the child is not really in my linkset.
325 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
326 {
327 if (m_children.Remove(child))
328 {
329 BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
330 BSPrimLinkable childx = child;
331
332 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
333 childx.LocalID,
334 rootx.LocalID, rootx.PhysBody.AddrString,
335 childx.LocalID, childx.PhysBody.AddrString);
336
337 m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate()
338 {
339 PhysicallyUnlinkAChildFromRoot(rootx, childx);
340 });
341 // See that the linkset parameters are recomputed at the end of the taint time.
342 Refresh(LinksetRoot);
343 }
344 else
345 {
346 // Non-fatal occurance.
347 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
348 }
349 return;
350 }
351
352 // Create a constraint between me (root of linkset) and the passed prim (the child).
353 // Called at taint time!
354 private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
355 {
356 // Don't build the constraint when asked. Put it off until just before the simulation step.
357 Refresh(rootPrim);
358 }
359
360 // Create a static constraint between the two passed objects
361 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
362 {
363 BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint;
364 if (linkInfo == null)
365 return null;
366
367 // Zero motion for children so they don't interpolate
368 li.member.ZeroMotion(true);
369
370 BSConstraint constrain = null;
371
372 switch (linkInfo.constraintType)
373 {
374 case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
375 case ConstraintType.D6_CONSTRAINT_TYPE:
376 // Relative position normalized to the root prim
377 // Essentually a vector pointing from center of rootPrim to center of li.member
378 OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position;
379
380 // real world coordinate of midpoint between the two objects
381 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
382
383 DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}",
384 rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody,
385 rootPrim.Position, linkInfo.member.Position, midPoint);
386
387 // create a constraint that allows no freedom of movement between the two objects
388 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
389
390 constrain = new BSConstraint6Dof(
391 m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true );
392
393 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
394 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
395 * of the objects.
396 * Code left for future programmers.
397 // ==================================================================================
398 // relative position normalized to the root prim
399 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
400 OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation;
401
402 // relative rotation of the child to the parent
403 OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation;
404 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
405
406 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID);
407 constrain = new BS6DofConstraint(
408 PhysicsScene.World, rootPrim.Body, liConstraint.member.Body,
409 OMV.Vector3.Zero,
410 OMV.Quaternion.Inverse(rootPrim.Orientation),
411 OMV.Vector3.Zero,
412 OMV.Quaternion.Inverse(liConstraint.member.Orientation),
413 true,
414 true
415 );
416 // ==================================================================================
417 */
418
419 break;
420 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
421 constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody,
422 linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot,
423 linkInfo.useLinearReferenceFrameA,
424 true /*disableCollisionsBetweenLinkedBodies*/);
425 DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}",
426 rootPrim.LocalID,
427 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
428 linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString,
429 rootPrim.Position, linkInfo.member.Position);
430
431 break;
432 default:
433 break;
434 }
435
436 linkInfo.SetLinkParameters(constrain);
437
438 m_physicsScene.Constraints.AddConstraint(constrain);
439
440 return constrain;
441 }
442
443 // Remove linkage between the linkset root and a particular child
444 // The root and child bodies are passed in because we need to remove the constraint between
445 // the bodies that were present at unlink time.
446 // Called at taint time!
447 private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
448 {
449 bool ret = false;
450 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
451 rootPrim.LocalID,
452 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
453 childPrim.LocalID, childPrim.PhysBody.AddrString);
454
455 // If asked to unlink root from root, just remove all the constraints
456 if (rootPrim == childPrim || childPrim == LinksetRoot)
457 {
458 PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
459 ret = true;
460 }
461 else
462 {
463 // Find the constraint for this link and get rid of it from the overall collection and from my list
464 if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
465 {
466 // Make the child refresh its location
467 m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
468 ret = true;
469 }
470 }
471
472 return ret;
473 }
474
475 // Remove linkage between myself and any possible children I might have.
476 // Returns 'true' of any constraints were destroyed.
477 // Called at taint time!
478 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
479 {
480 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
481
482 return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
483 }
484
485 // Call each of the constraints that make up this linkset and recompute the
486 // various transforms and variables. Create constraints of not created yet.
487 // Called before the simulation step to make sure the constraint based linkset
488 // is all initialized.
489 // Called at taint time!!
490 private void RecomputeLinksetConstraints()
491 {
492 float linksetMass = LinksetMass;
493 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
494
495 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
496 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
497
498 try
499 {
500 Rebuilding = true;
501
502 // There is no reason to build all this physical stuff for a non-physical linkset.
503 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
504 {
505 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
506 return; // Note the 'finally' clause at the botton which will get executed.
507 }
508
509 ForEachLinkInfo((li) =>
510 {
511 // A child in the linkset physically shows the mass of the whole linkset.
512 // This allows Bullet to apply enough force on the child to move the whole linkset.
513 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
514 li.member.UpdatePhysicalMassProperties(linksetMass, true);
515
516 BSConstraint constrain;
517 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain))
518 {
519 // If constraint doesn't exist yet, create it.
520 constrain = BuildConstraint(LinksetRoot, li);
521 }
522 li.SetLinkParameters(constrain);
523 constrain.RecomputeConstraintVariables(linksetMass);
524
525 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
526 return false; // 'false' says to keep processing other members
527 });
528 }
529 finally
530 {
531 Rebuilding = false;
532 }
533 }
534
535 #region Extension
536 public override object Extension(string pFunct, params object[] pParams)
537 {
538 object ret = null;
539 switch (pFunct)
540 {
541 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
542 case ExtendedPhysics.PhysFunctChangeLinkType:
543 if (pParams.Length > 2)
544 {
545 int requestedType = (int)pParams[2];
546 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType);
547 if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE
548 || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE
549 || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE
550 || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE
551 || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE
552 || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE)
553 {
554 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
555 if (child != null)
556 {
557 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}",
558 LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType);
559 m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate()
560 {
561 // Pick up all the constraints currently created.
562 RemoveDependencies(child);
563
564 BSLinkInfo linkInfo = null;
565 if (TryGetLinkInfo(child, out linkInfo))
566 {
567 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
568 if (linkInfoC != null)
569 {
570 linkInfoC.constraintType = (ConstraintType)requestedType;
571 ret = (object)true;
572 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}",
573 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
574 }
575 else
576 {
577 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID);
578 }
579 }
580 else
581 {
582 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID);
583 }
584 // Cause the whole linkset to be rebuilt in post-taint time.
585 Refresh(child);
586 });
587 }
588 else
589 {
590 DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID);
591 }
592 }
593 else
594 {
595 DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}",
596 LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE));
597 }
598 }
599 break;
600 // pParams = [ BSPhysObject root, BSPhysObject child ]
601 case ExtendedPhysics.PhysFunctGetLinkType:
602 if (pParams.Length > 0)
603 {
604 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
605 if (child != null)
606 {
607 BSLinkInfo linkInfo = null;
608 if (TryGetLinkInfo(child, out linkInfo))
609 {
610 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
611 if (linkInfoC != null)
612 {
613 ret = (object)(int)linkInfoC.constraintType;
614 DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}",
615 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
616
617 }
618 }
619 }
620 }
621 break;
622 // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ]
623 case ExtendedPhysics.PhysFunctChangeLinkParams:
624 // There should be two parameters: the childActor and a list of parameters to set
625 if (pParams.Length > 2)
626 {
627 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
628 BSLinkInfo baseLinkInfo = null;
629 if (TryGetLinkInfo(child, out baseLinkInfo))
630 {
631 BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint;
632 if (linkInfo != null)
633 {
634 int valueInt;
635 float valueFloat;
636 bool valueBool;
637 OMV.Vector3 valueVector;
638 OMV.Vector3 valueVector2;
639 OMV.Quaternion valueQuaternion;
640 int axisLow, axisHigh;
641
642 int opIndex = 2;
643 while (opIndex < pParams.Length)
644 {
645 int thisOp = 0;
646 string errMsg = "";
647 try
648 {
649 thisOp = (int)pParams[opIndex];
650 DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}",
651 linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]);
652 switch (thisOp)
653 {
654 case ExtendedPhysics.PHYS_PARAM_LINK_TYPE:
655 valueInt = (int)pParams[opIndex + 1];
656 ConstraintType valueType = (ConstraintType)valueInt;
657 if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE
658 || valueType == ConstraintType.D6_CONSTRAINT_TYPE
659 || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE
660 || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE
661 || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE
662 || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE)
663 {
664 linkInfo.constraintType = valueType;
665 }
666 opIndex += 2;
667 break;
668 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC:
669 errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector";
670 valueVector = (OMV.Vector3)pParams[opIndex + 1];
671 linkInfo.frameInAloc = valueVector;
672 opIndex += 2;
673 break;
674 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT:
675 errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation";
676 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
677 linkInfo.frameInArot = valueQuaternion;
678 opIndex += 2;
679 break;
680 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC:
681 errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector";
682 valueVector = (OMV.Vector3)pParams[opIndex + 1];
683 linkInfo.frameInBloc = valueVector;
684 opIndex += 2;
685 break;
686 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT:
687 errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation";
688 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
689 linkInfo.frameInBrot = valueQuaternion;
690 opIndex += 2;
691 break;
692 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW:
693 errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector";
694 valueVector = (OMV.Vector3)pParams[opIndex + 1];
695 linkInfo.linearLimitLow = valueVector;
696 opIndex += 2;
697 break;
698 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH:
699 errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector";
700 valueVector = (OMV.Vector3)pParams[opIndex + 1];
701 linkInfo.linearLimitHigh = valueVector;
702 opIndex += 2;
703 break;
704 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW:
705 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector";
706 valueVector = (OMV.Vector3)pParams[opIndex + 1];
707 linkInfo.angularLimitLow = valueVector;
708 opIndex += 2;
709 break;
710 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH:
711 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector";
712 valueVector = (OMV.Vector3)pParams[opIndex + 1];
713 linkInfo.angularLimitHigh = valueVector;
714 opIndex += 2;
715 break;
716 case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET:
717 errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)";
718 valueBool = ((int)pParams[opIndex + 1]) != 0;
719 linkInfo.useFrameOffset = valueBool;
720 opIndex += 2;
721 break;
722 case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR:
723 errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)";
724 valueBool = ((int)pParams[opIndex + 1]) != 0;
725 linkInfo.enableTransMotor = valueBool;
726 opIndex += 2;
727 break;
728 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL:
729 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float";
730 valueFloat = (float)pParams[opIndex + 1];
731 linkInfo.transMotorMaxVel = valueFloat;
732 opIndex += 2;
733 break;
734 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE:
735 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float";
736 valueFloat = (float)pParams[opIndex + 1];
737 linkInfo.transMotorMaxForce = valueFloat;
738 opIndex += 2;
739 break;
740 case ExtendedPhysics.PHYS_PARAM_CFM:
741 errMsg = "PHYS_PARAM_CFM takes one parameter of type float";
742 valueFloat = (float)pParams[opIndex + 1];
743 linkInfo.cfm = valueFloat;
744 opIndex += 2;
745 break;
746 case ExtendedPhysics.PHYS_PARAM_ERP:
747 errMsg = "PHYS_PARAM_ERP takes one parameter of type float";
748 valueFloat = (float)pParams[opIndex + 1];
749 linkInfo.erp = valueFloat;
750 opIndex += 2;
751 break;
752 case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS:
753 errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float";
754 valueFloat = (float)pParams[opIndex + 1];
755 linkInfo.solverIterations = valueFloat;
756 opIndex += 2;
757 break;
758 case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE:
759 errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)";
760 valueInt = (int)pParams[opIndex + 1];
761 valueBool = ((int)pParams[opIndex + 2]) != 0;
762 GetAxisRange(valueInt, out axisLow, out axisHigh);
763 for (int ii = axisLow; ii <= axisHigh; ii++)
764 linkInfo.springAxisEnable[ii] = valueBool;
765 opIndex += 3;
766 break;
767 case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING:
768 errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float";
769 valueInt = (int)pParams[opIndex + 1];
770 valueFloat = (float)pParams[opIndex + 2];
771 GetAxisRange(valueInt, out axisLow, out axisHigh);
772 for (int ii = axisLow; ii <= axisHigh; ii++)
773 linkInfo.springDamping[ii] = valueFloat;
774 opIndex += 3;
775 break;
776 case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS:
777 errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float";
778 valueInt = (int)pParams[opIndex + 1];
779 valueFloat = (float)pParams[opIndex + 2];
780 GetAxisRange(valueInt, out axisLow, out axisHigh);
781 for (int ii = axisLow; ii <= axisHigh; ii++)
782 linkInfo.springStiffness[ii] = valueFloat;
783 opIndex += 3;
784 break;
785 case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT:
786 errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector";
787 valueVector = (OMV.Vector3)pParams[opIndex + 1];
788 valueVector2 = (OMV.Vector3)pParams[opIndex + 2];
789 linkInfo.springLinearEquilibriumPoint = valueVector;
790 linkInfo.springAngularEquilibriumPoint = valueVector2;
791 opIndex += 3;
792 break;
793 case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA:
794 errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)";
795 valueBool = ((int)pParams[opIndex + 1]) != 0;
796 linkInfo.useLinearReferenceFrameA = valueBool;
797 opIndex += 2;
798 break;
799 default:
800 break;
801 }
802 }
803 catch (InvalidCastException e)
804 {
805 m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}",
806 LogHeader, errMsg, e);
807 }
808 catch (Exception e)
809 {
810 m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e);
811 }
812 }
813 }
814 // Something changed so a rebuild is in order
815 Refresh(child);
816 }
817 }
818 break;
819 default:
820 ret = base.Extension(pFunct, pParams);
821 break;
822 }
823 return ret;
824 }
825
826 // Bullet constraints keep some limit parameters for each linear and angular axis.
827 // Setting same is easier if there is an easy way to see all or types.
828 // This routine returns the array limits for the set of axis.
829 private void GetAxisRange(int rangeSpec, out int low, out int high)
830 {
831 switch (rangeSpec)
832 {
833 case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL:
834 low = 0;
835 high = 2;
836 break;
837 case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL:
838 low = 3;
839 high = 5;
840 break;
841 case ExtendedPhysics.PHYS_AXIS_ALL:
842 low = 0;
843 high = 5;
844 break;
845 default:
846 low = high = rangeSpec;
847 break;
848 }
849 return;
850 }
851 #endregion // Extension
852
853}
854}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
new file mode 100755
index 0000000..ee77d6e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
@@ -0,0 +1,203 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using System.Reflection;
31using Nini.Config;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public struct MaterialAttributes
37{
38 // Material type values that correspond with definitions for LSL
39 public enum Material : int
40 {
41 Stone = 0,
42 Metal,
43 Glass,
44 Wood,
45 Flesh,
46 Plastic,
47 Rubber,
48 Light,
49 // Hereafter are BulletSim additions
50 Avatar,
51 NumberOfTypes // the count of types in the enum.
52 }
53
54 // Names must be in the order of the above enum.
55 // These names must coorespond to the lower case field names in the MaterialAttributes
56 // structure as reflection is used to select the field to put the value in.
57 public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
58
59 public MaterialAttributes(string t, float d, float f, float r)
60 {
61 type = t;
62 density = d;
63 friction = f;
64 restitution = r;
65 }
66 public string type;
67 public float density;
68 public float friction;
69 public float restitution;
70}
71
72public static class BSMaterials
73{
74 // Attributes for each material type
75 private static readonly MaterialAttributes[] Attributes;
76
77 // Map of material name to material type code
78 public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap;
79
80 static BSMaterials()
81 {
82 // Attribute sets for both the non-physical and physical instances of materials.
83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
84
85 // Map of name to type code.
86 MaterialMap = new Dictionary<string, MaterialAttributes.Material>();
87 MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
88 MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
89 MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
90 MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
91 MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
92 MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
93 MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
94 MaterialMap.Add("Light", MaterialAttributes.Material.Light);
95 MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
96 }
97
98 // This is where all the default material attributes are defined.
99 public static void InitializeFromDefaults(ConfigurationParameters parms)
100 {
101 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
102 float dDensity = parms.defaultDensity;
103 float dFriction = parms.defaultFriction;
104 float dRestitution = parms.defaultRestitution;
105 Attributes[(int)MaterialAttributes.Material.Stone] =
106 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
107 Attributes[(int)MaterialAttributes.Material.Metal] =
108 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
109 Attributes[(int)MaterialAttributes.Material.Glass] =
110 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
111 Attributes[(int)MaterialAttributes.Material.Wood] =
112 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
113 Attributes[(int)MaterialAttributes.Material.Flesh] =
114 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
115 Attributes[(int)MaterialAttributes.Material.Plastic] =
116 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
117 Attributes[(int)MaterialAttributes.Material.Rubber] =
118 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
119 Attributes[(int)MaterialAttributes.Material.Light] =
120 new MaterialAttributes("light",dDensity, dFriction, dRestitution);
121 Attributes[(int)MaterialAttributes.Material.Avatar] =
122 new MaterialAttributes("avatar",3.5f, 0.2f, 0f);
123
124 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
125 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
126 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
127 new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f);
128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
129 new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f);
130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
131 new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f);
132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
133 new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f);
134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
135 new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f);
136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
137 new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f);
138 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
139 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
140 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
141 new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f);
142 }
143
144 // Under the [BulletSim] section, one can change the individual material
145 // attribute values. The format of the configuration parameter is:
146 // <materialName><Attribute>["Physical"] = floatValue
147 // For instance:
148 // [BulletSim]
149 // StoneFriction = 0.2
150 // FleshRestitutionPhysical = 0.8
151 // Materials can have different parameters for their static and
152 // physical instantiations. When setting the non-physical value,
153 // both values are changed. Setting the physical value only changes
154 // the physical value.
155 public static void InitializefromParameters(IConfig pConfig)
156 {
157 foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap)
158 {
159 string matName = kvp.Key;
160 foreach (string attribName in MaterialAttributes.MaterialAttribs)
161 {
162 string paramName = matName + attribName;
163 if (pConfig.Contains(paramName))
164 {
165 float paramValue = pConfig.GetFloat(paramName);
166 SetAttributeValue((int)kvp.Value, attribName, paramValue);
167 // set the physical value also
168 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
169 }
170 paramName += "Physical";
171 if (pConfig.Contains(paramName))
172 {
173 float paramValue = pConfig.GetFloat(paramName);
174 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
175 }
176 }
177 }
178 }
179
180 // Use reflection to set the value in the attribute structure.
181 private static void SetAttributeValue(int matType, string attribName, float val)
182 {
183 // Get the current attribute values for this material
184 MaterialAttributes thisAttrib = Attributes[matType];
185 // Find the field for the passed attribute name (eg, find field named 'friction')
186 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
187 if (fieldInfo != null)
188 {
189 fieldInfo.SetValue(thisAttrib, val);
190 // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
191 Attributes[matType] = thisAttrib;
192 }
193 }
194
195 // Given a material type, return a structure of attributes.
196 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
197 {
198 int ind = (int)type;
199 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
200 return Attributes[ind];
201 }
202}
203}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
new file mode 100755
index 0000000..7693195
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
@@ -0,0 +1,451 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28using System;
29using System.Collections.Generic;
30using System.Text;
31using OpenMetaverse;
32using OpenSim.Framework;
33
34namespace OpenSim.Region.Physics.BulletSPlugin
35{
36public abstract class BSMotor
37{
38 // Timescales and other things can be turned off by setting them to 'infinite'.
39 public const float Infinite = 12345.6f;
40 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
41
42 public BSMotor(string useName)
43 {
44 UseName = useName;
45 PhysicsScene = null;
46 Enabled = true;
47 }
48 public virtual bool Enabled { get; set; }
49 public virtual void Reset() { }
50 public virtual void Zero() { }
51 public virtual void GenerateTestOutput(float timeStep) { }
52
53 // A name passed at motor creation for easily identifyable debugging messages.
54 public string UseName { get; private set; }
55
56 // Used only for outputting debug information. Might not be set so check for null.
57 public BSScene PhysicsScene { get; set; }
58 protected void MDetailLog(string msg, params Object[] parms)
59 {
60 if (PhysicsScene != null)
61 {
62 PhysicsScene.DetailLog(msg, parms);
63 }
64 }
65}
66
67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
68// The TargetValue decays in TargetValueDecayTimeScale.
69// This motor will "zero itself" over time in that the targetValue will
70// decay to zero and the currentValue will follow it to that zero.
71// The overall effect is for the returned correction value to go from large
72// values to small and eventually zero values.
73// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
74
75// For instance, if something is moving at speed X and the desired speed is Y,
76// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
77// values of CurrentValue are returned that approach the TargetValue.
78// The feature of decaying TargetValue is so vehicles will eventually
79// come to a stop rather than run forever. This can be disabled by
80// setting TargetValueDecayTimescale to 'infinite'.
81// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
82public class BSVMotor : BSMotor
83{
84 // public Vector3 FrameOfReference { get; set; }
85 // public Vector3 Offset { get; set; }
86
87 public virtual float TimeScale { get; set; }
88 public virtual float TargetValueDecayTimeScale { get; set; }
89 public virtual float Efficiency { get; set; }
90
91 public virtual float ErrorZeroThreshold { get; set; }
92
93 public virtual Vector3 TargetValue { get; protected set; }
94 public virtual Vector3 CurrentValue { get; protected set; }
95 public virtual Vector3 LastError { get; protected set; }
96
97 public virtual bool ErrorIsZero()
98 {
99 return ErrorIsZero(LastError);
100 }
101 public virtual bool ErrorIsZero(Vector3 err)
102 {
103 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
104 }
105
106 public BSVMotor(string useName)
107 : base(useName)
108 {
109 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
110 Efficiency = 1f;
111 CurrentValue = TargetValue = Vector3.Zero;
112 ErrorZeroThreshold = 0.001f;
113 }
114 public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency)
115 : this(useName)
116 {
117 TimeScale = timeScale;
118 TargetValueDecayTimeScale = decayTimeScale;
119 Efficiency = efficiency;
120 CurrentValue = TargetValue = Vector3.Zero;
121 }
122 public void SetCurrent(Vector3 current)
123 {
124 CurrentValue = current;
125 }
126 public void SetTarget(Vector3 target)
127 {
128 TargetValue = target;
129 }
130 public override void Zero()
131 {
132 base.Zero();
133 CurrentValue = TargetValue = Vector3.Zero;
134 }
135
136 // Compute the next step and return the new current value.
137 // Returns the correction needed to move 'current' to 'target'.
138 public virtual Vector3 Step(float timeStep)
139 {
140 if (!Enabled) return TargetValue;
141
142 Vector3 origTarget = TargetValue; // DEBUG
143 Vector3 origCurrVal = CurrentValue; // DEBUG
144
145 Vector3 correction = Vector3.Zero;
146 Vector3 error = TargetValue - CurrentValue;
147 if (!ErrorIsZero(error))
148 {
149 correction = StepError(timeStep, error);
150
151 CurrentValue += correction;
152
153 // The desired value reduces to zero which also reduces the difference with current.
154 // If the decay time is infinite, don't decay at all.
155 float decayFactor = 0f;
156 if (TargetValueDecayTimeScale != BSMotor.Infinite)
157 {
158 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
159 TargetValue *= (1f - decayFactor);
160 }
161
162 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
163 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
164 timeStep, error, correction);
165 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
166 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
167 }
168 else
169 {
170 // Difference between what we have and target is small. Motor is done.
171 if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
172 {
173 // The target can step down to nearly zero but not get there. If close to zero
174 // it is really zero.
175 TargetValue = Vector3.Zero;
176 }
177 CurrentValue = TargetValue;
178 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
179 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
180 }
181 LastError = error;
182
183 return correction;
184 }
185 // version of step that sets the current value before doing the step
186 public virtual Vector3 Step(float timeStep, Vector3 current)
187 {
188 CurrentValue = current;
189 return Step(timeStep);
190 }
191 // Given and error, computer a correction for this step.
192 // Simple scaling of the error by the timestep.
193 public virtual Vector3 StepError(float timeStep, Vector3 error)
194 {
195 if (!Enabled) return Vector3.Zero;
196
197 Vector3 returnCorrection = Vector3.Zero;
198 if (!ErrorIsZero(error))
199 {
200 // correction = error / secondsItShouldTakeToCorrect
201 Vector3 correctionAmount;
202 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
203 correctionAmount = error * timeStep;
204 else
205 correctionAmount = error / TimeScale * timeStep;
206
207 returnCorrection = correctionAmount;
208 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
209 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
210 }
211 return returnCorrection;
212 }
213
214 // The user sets all the parameters and calls this which outputs values until error is zero.
215 public override void GenerateTestOutput(float timeStep)
216 {
217 // maximum number of outputs to generate.
218 int maxOutput = 50;
219 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
220 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}",
221 BSScene.DetailLogZero, UseName,
222 TimeScale, TargetValueDecayTimeScale, Efficiency,
223 CurrentValue, TargetValue);
224
225 LastError = BSMotor.InfiniteVector;
226 while (maxOutput-- > 0 && !ErrorIsZero())
227 {
228 Vector3 lastStep = Step(timeStep);
229 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
230 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
231 }
232 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
233
234
235 }
236
237 public override string ToString()
238 {
239 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
240 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
241 }
242}
243
244// ============================================================================
245// ============================================================================
246public class BSFMotor : BSMotor
247{
248 public virtual float TimeScale { get; set; }
249 public virtual float TargetValueDecayTimeScale { get; set; }
250 public virtual float Efficiency { get; set; }
251
252 public virtual float ErrorZeroThreshold { get; set; }
253
254 public virtual float TargetValue { get; protected set; }
255 public virtual float CurrentValue { get; protected set; }
256 public virtual float LastError { get; protected set; }
257
258 public virtual bool ErrorIsZero()
259 {
260 return ErrorIsZero(LastError);
261 }
262 public virtual bool ErrorIsZero(float err)
263 {
264 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
265 }
266
267 public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency)
268 : base(useName)
269 {
270 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
271 Efficiency = 1f;
272 CurrentValue = TargetValue = 0f;
273 ErrorZeroThreshold = 0.01f;
274 }
275 public void SetCurrent(float current)
276 {
277 CurrentValue = current;
278 }
279 public void SetTarget(float target)
280 {
281 TargetValue = target;
282 }
283 public override void Zero()
284 {
285 base.Zero();
286 CurrentValue = TargetValue = 0f;
287 }
288
289 public virtual float Step(float timeStep)
290 {
291 if (!Enabled) return TargetValue;
292
293 float origTarget = TargetValue; // DEBUG
294 float origCurrVal = CurrentValue; // DEBUG
295
296 float correction = 0f;
297 float error = TargetValue - CurrentValue;
298 if (!ErrorIsZero(error))
299 {
300 correction = StepError(timeStep, error);
301
302 CurrentValue += correction;
303
304 // The desired value reduces to zero which also reduces the difference with current.
305 // If the decay time is infinite, don't decay at all.
306 float decayFactor = 0f;
307 if (TargetValueDecayTimeScale != BSMotor.Infinite)
308 {
309 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
310 TargetValue *= (1f - decayFactor);
311 }
312
313 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
314 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
315 timeStep, error, correction);
316 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
317 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
318 }
319 else
320 {
321 // Difference between what we have and target is small. Motor is done.
322 if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold))
323 {
324 // The target can step down to nearly zero but not get there. If close to zero
325 // it is really zero.
326 TargetValue = 0f;
327 }
328 CurrentValue = TargetValue;
329 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
330 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
331 }
332 LastError = error;
333
334 return CurrentValue;
335 }
336
337 public virtual float StepError(float timeStep, float error)
338 {
339 if (!Enabled) return 0f;
340
341 float returnCorrection = 0f;
342 if (!ErrorIsZero(error))
343 {
344 // correction = error / secondsItShouldTakeToCorrect
345 float correctionAmount;
346 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
347 correctionAmount = error * timeStep;
348 else
349 correctionAmount = error / TimeScale * timeStep;
350
351 returnCorrection = correctionAmount;
352 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
353 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
354 }
355 return returnCorrection;
356 }
357
358 public override string ToString()
359 {
360 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
361 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
362 }
363
364}
365
366// ============================================================================
367// ============================================================================
368// Proportional, Integral, Derivitive ("PID") Motor
369// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
370public class BSPIDVMotor : BSVMotor
371{
372 // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
373 public Vector3 proportionFactor { get; set; }
374 public Vector3 integralFactor { get; set; }
375 public Vector3 derivFactor { get; set; }
376
377 // The factors are vectors for the three dimensions. This is the proportional of each
378 // that is applied. This could be multiplied through the actual factors but it
379 // is sometimes easier to manipulate the factors and their mix separately.
380 public Vector3 FactorMix;
381
382 // Arbritrary factor range.
383 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
384 public float EfficiencyHigh = 0.4f;
385 public float EfficiencyLow = 4.0f;
386
387 // Running integration of the error
388 Vector3 RunningIntegration { get; set; }
389
390 public BSPIDVMotor(string useName)
391 : base(useName)
392 {
393 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
394 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
395 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
396 FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
397 RunningIntegration = Vector3.Zero;
398 LastError = Vector3.Zero;
399 }
400
401 public override void Zero()
402 {
403 base.Zero();
404 }
405
406 public override float Efficiency
407 {
408 get { return base.Efficiency; }
409 set
410 {
411 base.Efficiency = Util.Clamp(value, 0f, 1f);
412
413 // Compute factors based on efficiency.
414 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
415 // If efficiency is low (0f), use a factor value that overcorrects.
416 // TODO: might want to vary contribution of different factor depending on efficiency.
417 // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
418 float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
419
420 proportionFactor = new Vector3(factor, factor, factor);
421 integralFactor = new Vector3(factor, factor, factor);
422 derivFactor = new Vector3(factor, factor, factor);
423
424 MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
425 }
426 }
427
428 // Advance the PID computation on this error.
429 public override Vector3 StepError(float timeStep, Vector3 error)
430 {
431 if (!Enabled) return Vector3.Zero;
432
433 // Add up the error so we can integrate over the accumulated errors
434 RunningIntegration += error * timeStep;
435
436 // A simple derivitive is the rate of change from the last error.
437 Vector3 derivitive = (error - LastError) * timeStep;
438
439 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
440 Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X
441 + RunningIntegration / TimeScale * integralFactor * FactorMix.Y
442 + derivitive / TimeScale * derivFactor * FactorMix.Z
443 ;
444
445 MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}",
446 BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret);
447
448 return ret;
449 }
450}
451}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
new file mode 100755
index 0000000..6d46fe6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
@@ -0,0 +1,927 @@
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.Text;
31
32using OpenSim.Region.Physics.Manager;
33
34using OpenMetaverse;
35using Nini.Config;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public static class BSParam
40{
41 private static string LogHeader = "[BULLETSIM PARAMETERS]";
42
43 // Tuning notes:
44 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
45 // Contact points can be added even if the distance is positive. The constraint solver can deal with
46 // contacts with positive distances as well as negative (penetration). Contact points are discarded
47 // if the distance exceeds a certain threshold.
48 // Bullet has a contact processing threshold and a contact breaking threshold.
49 // If the distance is larger than the contact breaking threshold, it will be removed after one frame.
50 // If the distance is larger than the contact processing threshold, the constraint solver will ignore it.
51
52 // This is separate/independent from the collision margin. The collision margin increases the object a bit
53 // to improve collision detection performance and accuracy.
54 // ===================
55 // From:
56
57 /// <summary>
58 /// Set whether physics is active or not.
59 /// </summary>
60 /// <remarks>
61 /// Can be enabled and disabled to start and stop physics.
62 /// </remarks>
63 public static bool Active { get; private set; }
64
65 public static bool UseSeparatePhysicsThread { get; private set; }
66 public static float PhysicsTimeStep { get; private set; }
67
68 // Level of Detail values kept as float because that's what the Meshmerizer wants
69 public static float MeshLOD { get; private set; }
70 public static float MeshCircularLOD { get; private set; }
71 public static float MeshMegaPrimLOD { get; private set; }
72 public static float MeshMegaPrimThreshold { get; private set; }
73 public static float SculptLOD { get; private set; }
74
75 public static int CrossingFailuresBeforeOutOfBounds { get; private set; }
76 public static float UpdateVelocityChangeThreshold { get; private set; }
77
78 public static float MinimumObjectMass { get; private set; }
79 public static float MaximumObjectMass { get; private set; }
80 public static float MaxLinearVelocity { get; private set; }
81 public static float MaxLinearVelocitySquared { get; private set; }
82 public static float MaxAngularVelocity { get; private set; }
83 public static float MaxAngularVelocitySquared { get; private set; }
84 public static float MaxAddForceMagnitude { get; private set; }
85 public static float MaxAddForceMagnitudeSquared { get; private set; }
86 public static float DensityScaleFactor { get; private set; }
87
88 public static float LinearDamping { get; private set; }
89 public static float AngularDamping { get; private set; }
90 public static float DeactivationTime { get; private set; }
91 public static float LinearSleepingThreshold { get; private set; }
92 public static float AngularSleepingThreshold { get; private set; }
93 public static float CcdMotionThreshold { get; private set; }
94 public static float CcdSweptSphereRadius { get; private set; }
95 public static float ContactProcessingThreshold { get; private set; }
96
97 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
98 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
99 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
100 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
101 public static bool ShouldUseBulletHACD { get; set; }
102 public static bool ShouldUseSingleConvexHullForPrims { get; set; }
103 public static bool ShouldUseGImpactShapeForPrims { get; set; }
104 public static bool ShouldUseAssetHulls { get; set; }
105
106 public static float TerrainImplementation { get; set; }
107 public static int TerrainMeshMagnification { get; private set; }
108 public static float TerrainGroundPlane { get; private set; }
109 public static float TerrainFriction { get; private set; }
110 public static float TerrainHitFraction { get; private set; }
111 public static float TerrainRestitution { get; private set; }
112 public static float TerrainContactProcessingThreshold { get; private set; }
113 public static float TerrainCollisionMargin { get; private set; }
114
115 public static float DefaultFriction { get; private set; }
116 public static float DefaultDensity { get; private set; }
117 public static float DefaultRestitution { get; private set; }
118 public static float CollisionMargin { get; private set; }
119 public static float Gravity { get; private set; }
120
121 // Physics Engine operation
122 public static float MaxPersistantManifoldPoolSize { get; private set; }
123 public static float MaxCollisionAlgorithmPoolSize { get; private set; }
124 public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; }
125 public static bool ShouldForceUpdateAllAabbs { get; private set; }
126 public static bool ShouldRandomizeSolverOrder { get; private set; }
127 public static bool ShouldSplitSimulationIslands { get; private set; }
128 public static bool ShouldEnableFrictionCaching { get; private set; }
129 public static float NumberOfSolverIterations { get; private set; }
130 public static bool UseSingleSidedMeshes { get; private set; }
131 public static float GlobalContactBreakingThreshold { get; private set; }
132 public static float PhysicsUnmanLoggingFrames { get; private set; }
133
134 // Avatar parameters
135 public static bool AvatarToAvatarCollisionsByDefault { get; private set; }
136 public static float AvatarFriction { get; private set; }
137 public static float AvatarStandingFriction { get; private set; }
138 public static float AvatarAlwaysRunFactor { get; private set; }
139 public static float AvatarDensity { get; private set; }
140 public static float AvatarRestitution { get; private set; }
141 public static int AvatarShape { get; private set; }
142 public static float AvatarCapsuleWidth { get; private set; }
143 public static float AvatarCapsuleDepth { get; private set; }
144 public static float AvatarCapsuleHeight { get; private set; }
145 public static float AvatarHeightLowFudge { get; private set; }
146 public static float AvatarHeightMidFudge { get; private set; }
147 public static float AvatarHeightHighFudge { get; private set; }
148 public static float AvatarFlyingGroundMargin { get; private set; }
149 public static float AvatarFlyingGroundUpForce { get; private set; }
150 public static float AvatarTerminalVelocity { get; private set; }
151 public static float AvatarContactProcessingThreshold { get; private set; }
152 public static float AvatarStopZeroThreshold { get; private set; }
153 public static int AvatarJumpFrames { get; private set; }
154 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
155 public static float AvatarStepHeight { get; private set; }
156 public static float AvatarStepAngle { get; private set; }
157 public static float AvatarStepGroundFudge { get; private set; }
158 public static float AvatarStepApproachFactor { get; private set; }
159 public static float AvatarStepForceFactor { get; private set; }
160 public static float AvatarStepUpCorrectionFactor { get; private set; }
161 public static int AvatarStepSmoothingSteps { get; private set; }
162
163 // Vehicle parameters
164 public static float VehicleMaxLinearVelocity { get; private set; }
165 public static float VehicleMaxLinearVelocitySquared { get; private set; }
166 public static float VehicleMinLinearVelocity { get; private set; }
167 public static float VehicleMinLinearVelocitySquared { get; private set; }
168 public static float VehicleMaxAngularVelocity { get; private set; }
169 public static float VehicleMaxAngularVelocitySq { get; private set; }
170 public static float VehicleAngularDamping { get; private set; }
171 public static float VehicleFriction { get; private set; }
172 public static float VehicleRestitution { get; private set; }
173 public static Vector3 VehicleLinearFactor { get; private set; }
174 public static Vector3 VehicleAngularFactor { get; private set; }
175 public static Vector3 VehicleInertiaFactor { get; private set; }
176 public static float VehicleGroundGravityFudge { get; private set; }
177 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
178 public static bool VehicleEnableLinearDeflection { get; private set; }
179 public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; }
180 public static bool VehicleEnableAngularVerticalAttraction { get; private set; }
181 public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; }
182 public static bool VehicleEnableAngularDeflection { get; private set; }
183 public static bool VehicleEnableAngularBanking { get; private set; }
184
185 // Convex Hulls
186 // Parameters for convex hull routine that ships with Bullet
187 public static int CSHullMaxDepthSplit { get; private set; }
188 public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
189 public static float CSHullConcavityThresholdPercent { get; private set; }
190 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
191 public static int CSHullMaxVertices { get; private set; }
192 public static float CSHullMaxSkinWidth { get; private set; }
193 public static float BHullMaxVerticesPerHull { get; private set; } // 100
194 public static float BHullMinClusters { get; private set; } // 2
195 public static float BHullCompacityWeight { get; private set; } // 0.1
196 public static float BHullVolumeWeight { get; private set; } // 0.0
197 public static float BHullConcavity { get; private set; } // 100
198 public static bool BHullAddExtraDistPoints { get; private set; } // false
199 public static bool BHullAddNeighboursDistPoints { get; private set; } // false
200 public static bool BHullAddFacesPoints { get; private set; } // false
201 public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false
202 public static float WhichHACD { get; private set; } // zero if Bullet HACD, non-zero says VHACD
203 // Parameters for VHACD 2.0: http://code.google.com/p/v-hacd
204 // To enable, set both ShouldUseBulletHACD=true and WhichHACD=1
205 // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html
206 public static float VHACDresolution { get; private set; } // 100,000 max number of voxels generated during voxelization stage
207 public static float VHACDdepth { get; private set; } // 20 max number of clipping stages
208 public static float VHACDconcavity { get; private set; } // 0.0025 maximum concavity
209 public static float VHACDplaneDownsampling { get; private set; } // 4 granularity of search for best clipping plane
210 public static float VHACDconvexHullDownsampling { get; private set; } // 4 precision of hull gen process
211 public static float VHACDalpha { get; private set; } // 0.05 bias toward clipping along symmetry planes
212 public static float VHACDbeta { get; private set; } // 0.05 bias toward clipping along revolution axis
213 public static float VHACDgamma { get; private set; } // 0.00125 max concavity when merging
214 public static float VHACDpca { get; private set; } // 0 on/off normalizing mesh before decomp
215 public static float VHACDmode { get; private set; } // 0 0:voxel based, 1: tetrahedron based
216 public static float VHACDmaxNumVerticesPerCH { get; private set; } // 64 max triangles per convex hull
217 public static float VHACDminVolumePerCH { get; private set; } // 0.0001 sampling of generated convex hulls
218
219 // Linkset implementation parameters
220 public static float LinksetImplementation { get; private set; }
221 public static bool LinksetOffsetCenterOfMass { get; private set; }
222 public static bool LinkConstraintUseFrameOffset { get; private set; }
223 public static bool LinkConstraintEnableTransMotor { get; private set; }
224 public static float LinkConstraintTransMotorMaxVel { get; private set; }
225 public static float LinkConstraintTransMotorMaxForce { get; private set; }
226 public static float LinkConstraintERP { get; private set; }
227 public static float LinkConstraintCFM { get; private set; }
228 public static float LinkConstraintSolverIterations { get; private set; }
229
230 public static float PID_D { get; private set; } // derivative
231 public static float PID_P { get; private set; } // proportional
232
233 // Various constants that come from that other virtual world that shall not be named.
234 public const float MinGravityZ = -1f;
235 public const float MaxGravityZ = 28f;
236 public const float MinFriction = 0f;
237 public const float MaxFriction = 255f;
238 public const float MinDensity = 0.01f;
239 public const float MaxDensity = 22587f;
240 public const float MinRestitution = 0f;
241 public const float MaxRestitution = 1f;
242
243 // =====================================================================================
244 // =====================================================================================
245
246 // Base parameter definition that gets and sets parameter values via a string
247 public abstract class ParameterDefnBase
248 {
249 public string name; // string name of the parameter
250 public string desc; // a short description of what the parameter means
251 public ParameterDefnBase(string pName, string pDesc)
252 {
253 name = pName;
254 desc = pDesc;
255 }
256 // Set the parameter value to the default
257 public abstract void AssignDefault(BSScene s);
258 // Get the value as a string
259 public abstract string GetValue(BSScene s);
260 // Set the value to this string value
261 public abstract void SetValue(BSScene s, string valAsString);
262 // set the value on a particular object (usually sets in physics engine)
263 public abstract void SetOnObject(BSScene s, BSPhysObject obj);
264 public abstract bool HasSetOnObject { get; }
265 }
266
267 // Specific parameter definition for a parameter of a specific type.
268 public delegate T PGetValue<T>(BSScene s);
269 public delegate void PSetValue<T>(BSScene s, T val);
270 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
271 public sealed class ParameterDefn<T> : ParameterDefnBase
272 {
273 private T defaultValue;
274 private PSetValue<T> setter;
275 private PGetValue<T> getter;
276 private PSetOnObject<T> objectSet;
277 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
278 : base(pName, pDesc)
279 {
280 defaultValue = pDefault;
281 setter = pSetter;
282 getter = pGetter;
283 objectSet = null;
284 }
285 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter, PSetOnObject<T> pObjSetter)
286 : base(pName, pDesc)
287 {
288 defaultValue = pDefault;
289 setter = pSetter;
290 getter = pGetter;
291 objectSet = pObjSetter;
292 }
293 // Simple parameter variable where property name is the same as the INI file name
294 // and the value is only a simple get and set.
295 public ParameterDefn(string pName, string pDesc, T pDefault)
296 : base(pName, pDesc)
297 {
298 defaultValue = pDefault;
299 setter = (s, v) => { SetValueByName(s, name, v); };
300 getter = (s) => { return GetValueByName(s, name); };
301 objectSet = null;
302 }
303 // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same.
304 private void SetValueByName(BSScene s, string pName, T val)
305 {
306 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
307 if (prop == null)
308 {
309 // This should only be output when someone adds a new INI parameter and misspells the name.
310 s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName);
311 }
312 else
313 {
314 prop.SetValue(null, val, null);
315 }
316 }
317 // Use reflection to find the property named 'pName' in BSParam and return the value in same.
318 private T GetValueByName(BSScene s, string pName)
319 {
320 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
321 if (prop == null)
322 {
323 // This should only be output when someone adds a new INI parameter and misspells the name.
324 s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName);
325 }
326 return (T)prop.GetValue(null, null);
327 }
328 public override void AssignDefault(BSScene s)
329 {
330 setter(s, defaultValue);
331 }
332 public override string GetValue(BSScene s)
333 {
334 return getter(s).ToString();
335 }
336 public override void SetValue(BSScene s, string valAsString)
337 {
338 // Get the generic type of the setter
339 Type genericType = setter.GetType().GetGenericArguments()[0];
340 // Find the 'Parse' method on that type
341 System.Reflection.MethodInfo parser = null;
342 try
343 {
344 parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } );
345 }
346 catch (Exception e)
347 {
348 s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e);
349 parser = null;
350 }
351 if (parser != null)
352 {
353 // Parse the input string
354 try
355 {
356 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
357 // Store the parsed value
358 setter(s, setValue);
359 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
360 }
361 catch
362 {
363 s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType);
364 }
365 }
366 else
367 {
368 s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType);
369 }
370 }
371 public override bool HasSetOnObject
372 {
373 get { return objectSet != null; }
374 }
375 public override void SetOnObject(BSScene s, BSPhysObject obj)
376 {
377 if (objectSet != null)
378 objectSet(s, obj);
379 }
380 }
381
382 // List of all of the externally visible parameters.
383 // For each parameter, this table maps a text name to getter and setters.
384 // To add a new externally referencable/settable parameter, add the paramter storage
385 // location somewhere in the program and make an entry in this table with the
386 // getters and setters.
387 // It is easiest to find an existing definition and copy it.
388 //
389 // A ParameterDefn<T>() takes the following parameters:
390 // -- the text name of the parameter. This is used for console input and ini file.
391 // -- a short text description of the parameter. This shows up in the console listing.
392 // -- a default value
393 // -- a delegate for getting the value
394 // -- a delegate for setting the value
395 // -- an optional delegate to update the value in the world. Most often used to
396 // push the new value to an in-world object.
397 //
398 // The single letter parameters for the delegates are:
399 // s = BSScene
400 // o = BSPhysObject
401 // v = value (appropriate type)
402 private static ParameterDefnBase[] ParameterDefinitions =
403 {
404 new ParameterDefn<bool>("Active", "If 'true', false then physics is not active",
405 false ),
406 new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat",
407 false ),
408 new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval",
409 0.089f ),
410
411 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties",
412 true,
413 (s) => { return ShouldMeshSculptedPrim; },
414 (s,v) => { ShouldMeshSculptedPrim = v; } ),
415 new ParameterDefn<bool>("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
416 false,
417 (s) => { return ShouldForceSimplePrimMeshing; },
418 (s,v) => { ShouldForceSimplePrimMeshing = v; } ),
419 new ParameterDefn<bool>("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
420 true,
421 (s) => { return ShouldUseHullsForPhysicalObjects; },
422 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ),
423 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
424 true ),
425 new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD",
426 false ),
427 new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims",
428 true ),
429 new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists",
430 false ),
431 new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info",
432 true ),
433
434 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
435 5 ),
436 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator",
437 0.1f ),
438
439 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
440 32f,
441 (s) => { return MeshLOD; },
442 (s,v) => { MeshLOD = v; } ),
443 new ParameterDefn<float>("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes",
444 32f,
445 (s) => { return MeshCircularLOD; },
446 (s,v) => { MeshCircularLOD = v; } ),
447 new ParameterDefn<float>("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
448 10f,
449 (s) => { return MeshMegaPrimThreshold; },
450 (s,v) => { MeshMegaPrimThreshold = v; } ),
451 new ParameterDefn<float>("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
452 32f,
453 (s) => { return MeshMegaPrimLOD; },
454 (s,v) => { MeshMegaPrimLOD = v; } ),
455 new ParameterDefn<float>("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
456 32f,
457 (s) => { return SculptLOD; },
458 (s,v) => { SculptLOD = v; } ),
459
460 new ParameterDefn<int>("MaxSubStep", "In simulation step, maximum number of substeps",
461 10,
462 (s) => { return s.m_maxSubSteps; },
463 (s,v) => { s.m_maxSubSteps = (int)v; } ),
464 new ParameterDefn<float>("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
465 1f / 60f,
466 (s) => { return s.m_fixedTimeStep; },
467 (s,v) => { s.m_fixedTimeStep = v; } ),
468 new ParameterDefn<float>("NominalFrameRate", "The base frame rate we claim",
469 55f,
470 (s) => { return s.NominalFrameRate; },
471 (s,v) => { s.NominalFrameRate = (int)v; } ),
472 new ParameterDefn<int>("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
473 2048,
474 (s) => { return s.m_maxCollisionsPerFrame; },
475 (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
476 new ParameterDefn<int>("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
477 8000,
478 (s) => { return s.m_maxUpdatesPerFrame; },
479 (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
480
481 new ParameterDefn<float>("MinObjectMass", "Minimum object mass (0.0001)",
482 0.0001f,
483 (s) => { return MinimumObjectMass; },
484 (s,v) => { MinimumObjectMass = v; } ),
485 new ParameterDefn<float>("MaxObjectMass", "Maximum object mass (10000.01)",
486 10000.01f,
487 (s) => { return MaximumObjectMass; },
488 (s,v) => { MaximumObjectMass = v; } ),
489 new ParameterDefn<float>("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
490 1000.0f,
491 (s) => { return MaxLinearVelocity; },
492 (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ),
493 new ParameterDefn<float>("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
494 1000.0f,
495 (s) => { return MaxAngularVelocity; },
496 (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ),
497 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
498 new ParameterDefn<float>("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
499 20000.0f,
500 (s) => { return MaxAddForceMagnitude; },
501 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
502 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
503 // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well
504 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
505 0.01f ),
506
507 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
508 2200f ),
509 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing",
510 900f ),
511
512 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects",
513 0.2f,
514 (s) => { return DefaultFriction; },
515 (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ),
516 // For historical reasons, the viewer and simulator multiply the density by 100
517 new ParameterDefn<float>("DefaultDensity", "Density for new objects" ,
518 1000.0006836f, // Aluminum g/cm3 * 100
519 (s) => { return DefaultDensity; },
520 (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ),
521 new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" ,
522 0f,
523 (s) => { return DefaultRestitution; },
524 (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ),
525 new ParameterDefn<float>("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
526 0.04f,
527 (s) => { return CollisionMargin; },
528 (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ),
529 new ParameterDefn<float>("Gravity", "Vertical force of gravity (negative means down)",
530 -9.80665f,
531 (s) => { return Gravity; },
532 (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; },
533 (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ),
534
535
536 new ParameterDefn<float>("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
537 0f,
538 (s) => { return LinearDamping; },
539 (s,v) => { LinearDamping = v; },
540 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
541 new ParameterDefn<float>("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
542 0f,
543 (s) => { return AngularDamping; },
544 (s,v) => { AngularDamping = v; },
545 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
546 new ParameterDefn<float>("DeactivationTime", "Seconds before considering an object potentially static",
547 0.2f,
548 (s) => { return DeactivationTime; },
549 (s,v) => { DeactivationTime = v; },
550 (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ),
551 new ParameterDefn<float>("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
552 0.8f,
553 (s) => { return LinearSleepingThreshold; },
554 (s,v) => { LinearSleepingThreshold = v;},
555 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
556 new ParameterDefn<float>("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
557 1.0f,
558 (s) => { return AngularSleepingThreshold; },
559 (s,v) => { AngularSleepingThreshold = v;},
560 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
561 new ParameterDefn<float>("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
562 0.0f, // set to zero to disable
563 (s) => { return CcdMotionThreshold; },
564 (s,v) => { CcdMotionThreshold = v;},
565 (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ),
566 new ParameterDefn<float>("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
567 0.2f,
568 (s) => { return CcdSweptSphereRadius; },
569 (s,v) => { CcdSweptSphereRadius = v;},
570 (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ),
571 new ParameterDefn<float>("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" ,
572 0.0f,
573 (s) => { return ContactProcessingThreshold; },
574 (s,v) => { ContactProcessingThreshold = v;},
575 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
576
577 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
578 (float)BSTerrainPhys.TerrainImplementation.Heightmap ),
579 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
580 2 ),
581 new ParameterDefn<float>("TerrainGroundPlane", "Altitude of ground plane used to keep things from falling to infinity" ,
582 -500.0f ),
583 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
584 0.3f ),
585 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" ,
586 0.8f ),
587 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" ,
588 0f ),
589 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
590 0.0f ),
591 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
592 0.04f ),
593
594 new ParameterDefn<bool>("AvatarToAvatarCollisionsByDefault", "Should avatars collide with other avatars by default?",
595 true),
596 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
597 0.2f ),
598 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
599 0.95f ),
600 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
601 1.3f ),
602 // For historical reasons, density is reported * 100
603 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.",
604 3500f) , // 3.5 * 100
605 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
606 0f ),
607 new ParameterDefn<int>("AvatarShape", "Code for avatar physical shape: 0:capsule, 1:cube, 2:ovoid, 2:mesh",
608 BSShapeCollection.AvatarShapeCube ) ,
609 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
610 0.6f ) ,
611 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
612 0.45f ),
613 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar",
614 1.5f ),
615 new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
616 0f ),
617 new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
618 0f ),
619 new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
620 0f ),
621 new ParameterDefn<float>("AvatarFlyingGroundMargin", "Meters avatar is kept above the ground when flying",
622 5f ),
623 new ParameterDefn<float>("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin",
624 2.0f ),
625 new ParameterDefn<float>("AvatarTerminalVelocity", "Terminal Velocity of falling avatar",
626 -54.0f ),
627 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
628 0.1f ),
629 new ParameterDefn<float>("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped",
630 0.1f ),
631 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
632 1.0f ),
633 new ParameterDefn<int>("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.",
634 4 ),
635 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
636 0.999f ) ,
637 new ParameterDefn<float>("AvatarStepAngle", "The angle (in radians) for a vertical surface to be considered a step",
638 0.3f ) ,
639 new ParameterDefn<float>("AvatarStepGroundFudge", "Fudge factor subtracted from avatar base when comparing collision height",
640 0.1f ) ,
641 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
642 2f ),
643 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
644 0f ),
645 new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step",
646 0.8f ),
647 new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs",
648 1 ),
649
650 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
651 1000.0f,
652 (s) => { return (float)VehicleMaxLinearVelocity; },
653 (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ),
654 new ParameterDefn<float>("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
655 0.001f,
656 (s) => { return (float)VehicleMinLinearVelocity; },
657 (s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ),
658 new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
659 12.0f,
660 (s) => { return (float)VehicleMaxAngularVelocity; },
661 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ),
662 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
663 0.0f ),
664 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)",
665 new Vector3(1f, 1f, 1f) ),
666 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)",
667 new Vector3(1f, 1f, 1f) ),
668 new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)",
669 new Vector3(1f, 1f, 1f) ),
670 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)",
671 0.0f ),
672 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
673 0.0f ),
674 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
675 0.2f ),
676 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
677 60.0f ),
678 new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",
679 true ),
680 new ParameterDefn<bool>("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles",
681 true ),
682 new ParameterDefn<bool>("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect",
683 true ),
684 new ParameterDefn<int>("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.",
685 0 ),
686 new ParameterDefn<bool>("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect",
687 true ),
688 new ParameterDefn<bool>("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect",
689 true ),
690
691 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
692 0f,
693 (s) => { return MaxPersistantManifoldPoolSize; },
694 (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
695 new ParameterDefn<float>("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
696 0f,
697 (s) => { return MaxCollisionAlgorithmPoolSize; },
698 (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
699 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
700 false,
701 (s) => { return ShouldDisableContactPoolDynamicAllocation; },
702 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
703 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
704 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
705 false,
706 (s) => { return ShouldForceUpdateAllAabbs; },
707 (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ),
708 new ParameterDefn<bool>("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
709 true,
710 (s) => { return ShouldRandomizeSolverOrder; },
711 (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ),
712 new ParameterDefn<bool>("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
713 true,
714 (s) => { return ShouldSplitSimulationIslands; },
715 (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ),
716 new ParameterDefn<bool>("ShouldEnableFrictionCaching", "Enable friction computation caching",
717 true,
718 (s) => { return ShouldEnableFrictionCaching; },
719 (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ),
720 new ParameterDefn<float>("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
721 0f, // zero says use Bullet default
722 (s) => { return NumberOfSolverIterations; },
723 (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
724 new ParameterDefn<bool>("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.",
725 true,
726 (s) => { return UseSingleSidedMeshes; },
727 (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ),
728 new ParameterDefn<float>("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))",
729 0f,
730 (s) => { return GlobalContactBreakingThreshold; },
731 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
732 new ParameterDefn<float>("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics",
733 0f,
734 (s) => { return PhysicsUnmanLoggingFrames; },
735 (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ),
736
737 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
738 7 ),
739 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
740 2 ),
741 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
742 5f ),
743 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
744 5f ),
745 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
746 32 ),
747 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
748 0f ),
749
750 new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull",
751 200f ),
752 new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh",
753 10f ),
754 new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls",
755 20f ),
756 new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull",
757 0.1f ),
758 new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be",
759 10f ),
760 new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors",
761 true ),
762 new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls",
763 true ),
764 new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces",
765 true ),
766 new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
767 false ),
768
769 new ParameterDefn<float>("WhichHACD", "zero if Bullet HACD, non-zero says VHACD",
770 0f ),
771 new ParameterDefn<float>("VHACDresolution", "max number of voxels generated during voxelization stage",
772 100000f ),
773 new ParameterDefn<float>("VHACDdepth", "max number of clipping stages",
774 20f ),
775 new ParameterDefn<float>("VHACDconcavity", "maximum concavity",
776 0.0025f ),
777 new ParameterDefn<float>("VHACDplaneDownsampling", "granularity of search for best clipping plane",
778 4f ),
779 new ParameterDefn<float>("VHACDconvexHullDownsampling", "precision of hull gen process",
780 4f ),
781 new ParameterDefn<float>("VHACDalpha", "bias toward clipping along symmetry planes",
782 0.05f ),
783 new ParameterDefn<float>("VHACDbeta", "bias toward clipping along revolution axis",
784 0.05f ),
785 new ParameterDefn<float>("VHACDgamma", "max concavity when merging",
786 0.00125f ),
787 new ParameterDefn<float>("VHACDpca", "on/off normalizing mesh before decomp",
788 0f ),
789 new ParameterDefn<float>("VHACDmode", "0:voxel based, 1: tetrahedron based",
790 0f ),
791 new ParameterDefn<float>("VHACDmaxNumVerticesPerCH", "max triangles per convex hull",
792 64f ),
793 new ParameterDefn<float>("VHACDminVolumePerCH", "sampling of generated convex hulls",
794 0.0001f ),
795
796 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
797 (float)BSLinkset.LinksetImplementation.Compound ),
798 new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same",
799 true ),
800 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
801 false ),
802 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
803 true ),
804 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
805 5.0f ),
806 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
807 0.1f ),
808 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
809 0.1f ),
810 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
811 0.1f ),
812 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
813 40 ),
814
815 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
816 0,
817 (s) => { return s.PhysicsMetricDumpFrames; },
818 (s,v) => { s.PhysicsMetricDumpFrames = v; } ),
819 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
820 0f,
821 (s) => { return 0f; },
822 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ),
823 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
824 0f,
825 (s) => { return 0f; },
826 (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
827 };
828
829 // Convert a boolean to our numeric true and false values
830 public static float NumericBool(bool b)
831 {
832 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
833 }
834
835 // Convert numeric true and false values to a boolean
836 public static bool BoolNumeric(float b)
837 {
838 return (b == ConfigurationParameters.numericTrue ? true : false);
839 }
840
841 // Search through the parameter definitions and return the matching
842 // ParameterDefn structure.
843 // Case does not matter as names are compared after converting to lower case.
844 // Returns 'false' if the parameter is not found.
845 internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn)
846 {
847 bool ret = false;
848 ParameterDefnBase foundDefn = null;
849 string pName = paramName.ToLower();
850
851 foreach (ParameterDefnBase parm in ParameterDefinitions)
852 {
853 if (pName == parm.name.ToLower())
854 {
855 foundDefn = parm;
856 ret = true;
857 break;
858 }
859 }
860 defn = foundDefn;
861 return ret;
862 }
863
864 // Pass through the settable parameters and set the default values
865 internal static void SetParameterDefaultValues(BSScene physicsScene)
866 {
867 foreach (ParameterDefnBase parm in ParameterDefinitions)
868 {
869 parm.AssignDefault(physicsScene);
870 }
871 }
872
873 // Get user set values out of the ini file.
874 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
875 {
876 foreach (ParameterDefnBase parm in ParameterDefinitions)
877 {
878 parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene)));
879 }
880 }
881
882 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
883
884 // This creates an array in the correct format for returning the list of
885 // parameters. This is used by the 'list' option of the 'physics' command.
886 internal static void BuildParameterTable()
887 {
888 if (SettableParameters.Length < ParameterDefinitions.Length)
889 {
890 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
891 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
892 {
893 ParameterDefnBase pd = ParameterDefinitions[ii];
894 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
895 }
896
897 // make the list alphabetical for ease of finding anything
898 entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); });
899
900 SettableParameters = entries.ToArray();
901 }
902 }
903
904 // =====================================================================
905 // =====================================================================
906 // There are parameters that, when set, cause things to happen in the physics engine.
907 // This causes the broadphase collision cache to be cleared.
908 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime)
909 {
910 BSScene physScene = pPhysScene;
911 physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate()
912 {
913 physScene.PE.ResetBroadphasePool(physScene.World);
914 });
915 }
916
917 // This causes the constraint solver cache to be cleared and reset.
918 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
919 {
920 BSScene physScene = pPhysScene;
921 physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate()
922 {
923 physScene.PE.ResetConstraintSolver(physScene.World);
924 });
925 }
926}
927}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
new file mode 100755
index 0000000..90da7a6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
@@ -0,0 +1,620 @@
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 OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37/*
38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last one should only be referenced in taint-time.
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}
68public abstract class BSPhysObject : PhysicsActor
69{
70 protected BSPhysObject()
71 {
72 }
73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
74 {
75 IsInitialized = false;
76
77 PhysScene = parentScene;
78 LocalID = localID;
79 PhysObjectName = name;
80 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
81 TypeName = typeName;
82
83 // Oddity if object is destroyed and recreated very quickly it could still have the old body.
84 if (!PhysBody.HasPhysicalBody)
85 PhysBody = new BulletBody(localID);
86
87 // Clean out anything that might be in the physical actor list.
88 // Again, a workaround for destroying and recreating an object very quickly.
89 PhysicalActors.Dispose();
90
91 UserSetCenterOfMassDisplacement = null;
92
93 PrimAssetState = PrimAssetCondition.Unknown;
94
95 // Initialize variables kept in base.
96 // Beware that these cause taints to be queued whch can cause race conditions on startup.
97 GravModifier = 1.0f;
98 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
99 HoverActive = false;
100
101 // Default material type. Also sets Friction, Restitution and Density.
102 SetMaterial((int)MaterialAttributes.Material.Wood);
103
104 CollisionsLastTickStep = -1;
105
106 SubscribedEventsMs = 0;
107 // Crazy values that will never be true
108 CollidingStep = BSScene.NotASimulationStep;
109 CollidingGroundStep = BSScene.NotASimulationStep;
110 CollisionAccumulation = BSScene.NotASimulationStep;
111 ColliderIsMoving = false;
112 CollisionScore = 0;
113
114 // All axis free.
115 LockedLinearAxis = LockedAxisFree;
116 LockedAngularAxis = LockedAxisFree;
117 }
118
119 // Tell the object to clean up.
120 public virtual void Destroy()
121 {
122 PhysicalActors.Enable(false);
123 PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate()
124 {
125 PhysicalActors.Dispose();
126 });
127 }
128
129 public BSScene PhysScene { get; protected set; }
130 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
131 public string PhysObjectName { get; protected set; }
132 public string TypeName { get; protected set; }
133
134 // Set to 'true' when the object is completely initialized.
135 // This mostly prevents property updates and collisions until the object is completely here.
136 public bool IsInitialized { get; protected set; }
137
138 // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed.
139 // This test is used to prevent some updates to the object when it only partially exists.
140 // There are several reasons and object might be incomplete:
141 // Its underlying mesh/sculpty is an asset which must be fetched from the asset store
142 // It is a linkset who is being added to or removed from
143 // It is changing state (static to physical, for instance) which requires rebuilding
144 // This is a computed value based on the underlying physical object construction
145 abstract public bool IsIncomplete { get; }
146
147 // Return the object mass without calculating it or having side effects
148 public abstract float RawMass { get; }
149 // Set the raw mass but also update physical mass properties (inertia, ...)
150 // 'inWorld' true if the object has already been added to the dynamic world.
151 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
152
153 // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
154 public virtual OMV.Vector3 Gravity { get; set; }
155 // The last value calculated for the prim's inertia
156 public OMV.Vector3 Inertia { get; set; }
157
158 // Reference to the physical body (btCollisionObject) of this object
159 public BulletBody PhysBody = new BulletBody(0);
160 // Reference to the physical shape (btCollisionShape) of this object
161 public BSShape PhysShape = new BSShapeNull();
162
163 // The physical representation of the prim might require an asset fetch.
164 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
165 public enum PrimAssetCondition
166 {
167 Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched
168 }
169 public PrimAssetCondition PrimAssetState { get; set; }
170 public virtual bool AssetFailed()
171 {
172 return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch)
173 || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) );
174 }
175
176 // The objects base shape information. Null if not a prim type shape.
177 public PrimitiveBaseShape BaseShape { get; protected set; }
178
179 // When the physical properties are updated, an EntityProperty holds the update values.
180 // Keep the current and last EntityProperties to enable computation of differences
181 // between the current update and the previous values.
182 public EntityProperties CurrentEntityProperties { get; set; }
183 public EntityProperties LastEntityProperties { get; set; }
184
185 public virtual OMV.Vector3 Scale { get; set; }
186
187 // It can be confusing for an actor to know if it should move or update an object
188 // depeneding on the setting of 'selected', 'physical, ...
189 // This flag is the true test -- if true, the object is being acted on in the physical world
190 public abstract bool IsPhysicallyActive { get; }
191
192 // Detailed state of the object.
193 public abstract bool IsSolid { get; }
194 public abstract bool IsStatic { get; }
195 public abstract bool IsSelected { get; }
196 public abstract bool IsVolumeDetect { get; }
197
198 // Materialness
199 public MaterialAttributes.Material Material { get; private set; }
200 public override void SetMaterial(int material)
201 {
202 Material = (MaterialAttributes.Material)material;
203
204 // Setting the material sets the material attributes also.
205 // TODO: decide if this is necessary -- the simulator does this.
206 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
207 Friction = matAttrib.friction;
208 Restitution = matAttrib.restitution;
209 Density = matAttrib.density;
210 // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
211 }
212
213 public override float Density
214 {
215 get
216 {
217 return base.Density;
218 }
219 set
220 {
221 DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value);
222 base.Density = value;
223 }
224 }
225
226 // Stop all physical motion.
227 public abstract void ZeroMotion(bool inTaintTime);
228 public abstract void ZeroAngularMotion(bool inTaintTime);
229
230 // Update the physical location and motion of the object. Called with data from Bullet.
231 public abstract void UpdateProperties(EntityProperties entprop);
232
233 public virtual OMV.Vector3 RawPosition { get; set; }
234 public abstract OMV.Vector3 ForcePosition { get; set; }
235
236 public virtual OMV.Quaternion RawOrientation { get; set; }
237 public abstract OMV.Quaternion ForceOrientation { get; set; }
238
239 public virtual OMV.Vector3 RawVelocity { get; set; }
240 public abstract OMV.Vector3 ForceVelocity { get; set; }
241
242 public OMV.Vector3 RawForce { get; set; }
243 public OMV.Vector3 RawTorque { get; set; }
244 public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
245 {
246 AddAngularForce(force, pushforce, false);
247 }
248 public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
249 public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
250
251 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
252
253 public abstract float ForceBuoyancy { get; set; }
254
255 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
256
257 public override bool PIDActive
258 {
259 get { return MoveToTargetActive; }
260 set { MoveToTargetActive = value; }
261 }
262
263 public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
264 public override float PIDTau { set { MoveToTargetTau = value; } }
265
266 public bool MoveToTargetActive { get; set; }
267 public OMV.Vector3 MoveToTargetTarget { get; set; }
268 public float MoveToTargetTau { get; set; }
269
270 // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
271 public override bool PIDHoverActive { set { HoverActive = value; } }
272 public override float PIDHoverHeight { set { HoverHeight = value; } }
273 public override PIDHoverType PIDHoverType { set { HoverType = value; } }
274 public override float PIDHoverTau { set { HoverTau = value; } }
275
276 public bool HoverActive { get; set; }
277 public float HoverHeight { get; set; }
278 public PIDHoverType HoverType { get; set; }
279 public float HoverTau { get; set; }
280
281 // For RotLookAt
282 public override OMV.Quaternion APIDTarget { set { return; } }
283 public override bool APIDActive { set { return; } }
284 public override float APIDStrength { set { return; } }
285 public override float APIDDamping { set { return; } }
286
287 // The current velocity forward
288 public virtual float ForwardSpeed
289 {
290 get
291 {
292 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
293 return characterOrientedVelocity.X;
294 }
295 }
296 // The forward speed we are trying to achieve (TargetVelocity)
297 public virtual float TargetVelocitySpeed
298 {
299 get
300 {
301 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
302 return characterOrientedVelocity.X;
303 }
304 }
305
306 // The user can optionally set the center of mass. The user's setting will override any
307 // computed center-of-mass (like in linksets).
308 // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
309 public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
310
311 public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free.
312 public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free.
313 public const float FreeAxis = 1f;
314 public const float LockedAxis = 0f;
315 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
316
317 // If an axis is locked (flagged above) then the limits of that axis are specified here.
318 // Linear axis limits are relative to the object's starting coordinates.
319 // Angular limits are limited to -PI to +PI
320 public OMV.Vector3 LockedLinearAxisLow;
321 public OMV.Vector3 LockedLinearAxisHigh;
322 public OMV.Vector3 LockedAngularAxisLow;
323 public OMV.Vector3 LockedAngularAxisHigh;
324
325 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
326 // they need waking up when parameters are changed.
327 // Called in taint-time!!
328 public void ActivateIfPhysical(bool forceIt)
329 {
330 if (PhysBody.HasPhysicalBody)
331 {
332 if (IsPhysical)
333 {
334 // Physical objects might need activating
335 PhysScene.PE.Activate(PhysBody, forceIt);
336 }
337 else
338 {
339 // Clear the collision cache since we've changed some properties.
340 PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody);
341 }
342 }
343 }
344
345 // 'actors' act on the physical object to change or constrain its motion. These can range from
346 // hovering to complex vehicle motion.
347 // May be called at non-taint time as this just adds the actor to the action list and the real
348 // work is done during the simulation step.
349 // Note that, if the actor is already in the list and we are disabling same, the actor is just left
350 // in the list disabled.
351 public delegate BSActor CreateActor();
352 public void EnableActor(bool enableActor, string actorName, CreateActor creator)
353 {
354 lock (PhysicalActors)
355 {
356 BSActor theActor;
357 if (PhysicalActors.TryGetActor(actorName, out theActor))
358 {
359 // The actor already exists so just turn it on or off
360 DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
361 theActor.Enabled = enableActor;
362 }
363 else
364 {
365 // The actor does not exist. If it should, create it.
366 if (enableActor)
367 {
368 DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
369 theActor = creator();
370 PhysicalActors.Add(actorName, theActor);
371 theActor.Enabled = true;
372 }
373 else
374 {
375 DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
376 }
377 }
378 }
379 }
380
381 #region Collisions
382
383 // Requested number of milliseconds between collision events. Zero means disabled.
384 protected int SubscribedEventsMs { get; set; }
385 // Given subscription, the time that a collision may be passed up
386 protected int NextCollisionOkTime { get; set; }
387 // The simulation step that last had a collision
388 protected long CollidingStep { get; set; }
389 // The simulation step that last had a collision with the ground
390 protected long CollidingGroundStep { get; set; }
391 // The simulation step that last collided with an object
392 protected long CollidingObjectStep { get; set; }
393 // The collision flags we think are set in Bullet
394 protected CollisionFlags CurrentCollisionFlags { get; set; }
395 // On a collision, check the collider and remember if the last collider was moving
396 // Used to modify the standing of avatars (avatars on stationary things stand still)
397 public bool ColliderIsMoving;
398 // 'true' if the last collider was a volume detect object
399 public bool ColliderIsVolumeDetect;
400 // Used by BSCharacter to manage standing (and not slipping)
401 public bool IsStationary;
402
403 // Count of collisions for this object
404 protected long CollisionAccumulation { get; set; }
405
406 public override bool IsColliding {
407 get { return (CollidingStep == PhysScene.SimulationStep); }
408 set {
409 if (value)
410 CollidingStep = PhysScene.SimulationStep;
411 else
412 CollidingStep = BSScene.NotASimulationStep;
413 }
414 }
415 // Complex objects (like linksets) need to know if there is a collision on any part of
416 // their shape. 'IsColliding' has an existing definition of reporting a collision on
417 // only this specific prim or component of linksets.
418 // 'HasSomeCollision' is defined as reporting if there is a collision on any part of
419 // the complex body that this prim is the root of.
420 public virtual bool HasSomeCollision
421 {
422 get { return IsColliding; }
423 set { IsColliding = value; }
424 }
425 public override bool CollidingGround {
426 get { return (CollidingGroundStep == PhysScene.SimulationStep); }
427 set
428 {
429 if (value)
430 CollidingGroundStep = PhysScene.SimulationStep;
431 else
432 CollidingGroundStep = BSScene.NotASimulationStep;
433 }
434 }
435 public override bool CollidingObj {
436 get { return (CollidingObjectStep == PhysScene.SimulationStep); }
437 set {
438 if (value)
439 CollidingObjectStep = PhysScene.SimulationStep;
440 else
441 CollidingObjectStep = BSScene.NotASimulationStep;
442 }
443 }
444
445 // The collisions that have been collected for the next collision reporting (throttled by subscription)
446 protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate();
447 // This is the collision collection last reported to the Simulator.
448 public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate();
449 // Remember the collisions recorded in the last tick for fancy collision checking
450 // (like a BSCharacter walking up stairs).
451 public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate();
452 private long CollisionsLastTickStep = -1;
453
454 // The simulation step is telling this object about a collision.
455 // Return 'true' if a collision was processed and should be sent up.
456 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
457 // Called at taint time from within the Step() function
458 public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
459 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
460 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
461 {
462 bool ret = false;
463
464 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
465 CollidingStep = PhysScene.SimulationStep;
466 if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
467 {
468 CollidingGroundStep = PhysScene.SimulationStep;
469 }
470 else
471 {
472 CollidingObjectStep = PhysScene.SimulationStep;
473 }
474
475 CollisionAccumulation++;
476
477 // For movement tests, remember if we are colliding with an object that is moving.
478 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
479 ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false;
480
481 // Make a collection of the collisions that happened the last simulation tick.
482 // This is different than the collection created for sending up to the simulator as it is cleared every tick.
483 if (CollisionsLastTickStep != PhysScene.SimulationStep)
484 {
485 CollisionsLastTick = new CollisionEventUpdate();
486 CollisionsLastTickStep = PhysScene.SimulationStep;
487 }
488 CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
489
490 // If someone has subscribed for collision events log the collision so it will be reported up
491 if (SubscribedEvents()) {
492 lock (PhysScene.CollisionLock)
493 {
494 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
495 }
496 DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
497 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
498
499 ret = true;
500 }
501 return ret;
502 }
503
504 // Send the collected collisions into the simulator.
505 // Called at taint time from within the Step() function thus no locking problems
506 // with CollisionCollection and ObjectsWithNoMoreCollisions.
507 // Called with BSScene.CollisionLock locked to protect the collision lists.
508 // Return 'true' if there were some actual collisions passed up
509 public virtual bool SendCollisions()
510 {
511 bool ret = true;
512
513 // If no collisions this call but there were collisions last call, force the collision
514 // event to be happen right now so quick collision_end.
515 bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
516
517 // throttle the collisions to the number of milliseconds specified in the subscription
518 if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
519 {
520 NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
521
522 // We are called if we previously had collisions. If there are no collisions
523 // this time, send up one last empty event so OpenSim can sense collision end.
524 if (CollisionCollection.Count == 0)
525 {
526 // If I have no collisions this time, remove me from the list of objects with collisions.
527 ret = false;
528 }
529
530 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
531 base.SendCollisionUpdate(CollisionCollection);
532
533 // Remember the collisions from this tick for some collision specific processing.
534 CollisionsLastReported = CollisionCollection;
535
536 // The CollisionCollection instance is passed around in the simulator.
537 // Make sure we don't have a handle to that one and that a new one is used for next time.
538 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
539 // a race condition is created for the other users of this instance.
540 CollisionCollection = new CollisionEventUpdate();
541 }
542 return ret;
543 }
544
545 // Subscribe for collision events.
546 // Parameter is the millisecond rate the caller wishes collision events to occur.
547 public override void SubscribeEvents(int ms) {
548 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
549 SubscribedEventsMs = ms;
550 if (ms > 0)
551 {
552 // make sure first collision happens
553 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
554
555 PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate()
556 {
557 if (PhysBody.HasPhysicalBody)
558 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
559 });
560 }
561 else
562 {
563 // Subscribing for zero or less is the same as unsubscribing
564 UnSubscribeEvents();
565 }
566 }
567 public override void UnSubscribeEvents() {
568 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
569 SubscribedEventsMs = 0;
570 PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate()
571 {
572 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
573 if (PhysBody.HasPhysicalBody)
574 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
575 });
576 }
577 // Return 'true' if the simulator wants collision events
578 public override bool SubscribedEvents() {
579 return (SubscribedEventsMs > 0);
580 }
581 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
582 // each time called. So this is built to be light weight for each collision and to do
583 // all the processing when the user asks for the info.
584 public void ComputeCollisionScore()
585 {
586 // Scale the collision count by the time since the last collision.
587 // The "+1" prevents dividing by zero.
588 long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
589 CollisionScore = CollisionAccumulation / timeAgo;
590 }
591 public override float CollisionScore { get; set; }
592
593 #endregion // Collisions
594
595 #region Per Simulation Step actions
596
597 public BSActorCollection PhysicalActors = new BSActorCollection();
598
599 // When an update to the physical properties happens, this event is fired to let
600 // different actors to modify the update before it is passed around
601 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
602 public event PreUpdatePropertyAction OnPreUpdateProperty;
603 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
604 {
605 PreUpdatePropertyAction actions = OnPreUpdateProperty;
606 if (actions != null)
607 actions(ref entprop);
608 }
609
610 #endregion // Per Simulation Step actions
611
612 // High performance detailed logging routine used by the physical objects.
613 protected void DetailLog(string msg, params Object[] args)
614 {
615 if (PhysScene.PhysicsLogging.Enabled)
616 PhysScene.DetailLog(msg, args);
617 }
618
619}
620}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs
new file mode 100644
index 0000000..9442854
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs
@@ -0,0 +1,76 @@
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 OpenSim.Framework;
30using OpenSim.Region.Physics.Manager;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
40 /// The unmanaged library is compiled and linked statically with Bullet
41 /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit).
42 /// </summary>
43public class BSPlugin : IPhysicsPlugin
44{
45 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
46
47 private BSScene _mScene;
48
49 public BSPlugin()
50 {
51 }
52
53 public bool Init()
54 {
55 return true;
56 }
57
58 public PhysicsScene GetScene(String sceneIdentifier)
59 {
60 if (_mScene == null)
61 {
62 _mScene = new BSScene(GetName(), sceneIdentifier);
63 }
64 return (_mScene);
65 }
66
67 public string GetName()
68 {
69 return ("BulletSim");
70 }
71
72 public void Dispose()
73 {
74 }
75}
76}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
new file mode 100644
index 0000000..a00991f
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
@@ -0,0 +1,1896 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using System.Collections.Generic;
31using System.Xml;
32using log4net;
33using OMV = OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Physics.Manager;
36using OpenSim.Region.Physics.ConvexDecompositionDotNet;
37using OpenSim.Region.OptionalModules.Scripting; // for ExtendedPhysics
38
39namespace OpenSim.Region.Physics.BulletSPlugin
40{
41
42 [Serializable]
43public class BSPrim : BSPhysObject
44{
45 protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 private static readonly string LogHeader = "[BULLETS PRIM]";
47
48 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
50
51 private bool _grabbed;
52 private bool _isSelected;
53 private bool _isVolumeDetect;
54
55 private float _mass; // the mass of this object
56 private OMV.Vector3 _acceleration;
57 private int _physicsActorType;
58 private bool _isPhysical;
59 private bool _flying;
60 private bool _setAlwaysRun;
61 private bool _throttleUpdates;
62 private bool _floatOnWater;
63 private OMV.Vector3 _rotationalVelocity;
64 private bool _kinematic;
65 private float _buoyancy;
66
67 private int CrossingFailures { get; set; }
68
69 // Keep a handle to the vehicle actor so it is easy to set parameters on same.
70 public const string VehicleActorName = "BasicVehicle";
71
72 // Parameters for the hover actor
73 public const string HoverActorName = "BSPrim.HoverActor";
74 // Parameters for the axis lock actor
75 public const String LockedAxisActorName = "BSPrim.LockedAxis";
76 // Parameters for the move to target actor
77 public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor";
78 // Parameters for the setForce and setTorque actors
79 public const string SetForceActorName = "BSPrim.SetForceActor";
80 public const string SetTorqueActorName = "BSPrim.SetTorqueActor";
81
82 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
83 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
84 : base(parent_scene, localID, primName, "BSPrim")
85 {
86 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
87 _physicsActorType = (int)ActorTypes.Prim;
88 RawPosition = pos;
89 _size = size;
90 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
91 RawOrientation = rotation;
92 _buoyancy = 0f;
93 RawVelocity = OMV.Vector3.Zero;
94 _rotationalVelocity = OMV.Vector3.Zero;
95 BaseShape = pbs;
96 _isPhysical = pisPhysical;
97 _isVolumeDetect = false;
98
99 _mass = CalculateMass();
100
101 DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs));
102 // DetailLog("{0},BSPrim.constructor,call", LocalID);
103 // do the actual object creation at taint time
104 PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
105 {
106 // Make sure the object is being created with some sanity.
107 ExtremeSanityCheck(true /* inTaintTime */);
108
109 CreateGeomAndObject(true);
110
111 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
112
113 IsInitialized = true;
114 });
115 }
116
117 // called when this prim is being destroyed and we should free all the resources
118 public override void Destroy()
119 {
120 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
121 IsInitialized = false;
122
123 base.Destroy();
124
125 // Undo any vehicle properties
126 this.VehicleType = (int)Vehicle.TYPE_NONE;
127
128 PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate()
129 {
130 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
131 // If there are physical body and shape, release my use of same.
132 PhysScene.Shapes.DereferenceBody(PhysBody, null);
133 PhysBody.Clear();
134 PhysShape.Dereference(PhysScene);
135 PhysShape = new BSShapeNull();
136 });
137 }
138
139 // No one uses this property.
140 public override bool Stopped {
141 get { return false; }
142 }
143
144 public override bool IsIncomplete {
145 get {
146 return ShapeRebuildScheduled;
147 }
148 }
149
150 // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued.
151 // The prim is still available but its underlying shape will change soon.
152 // This is protected by a 'lock(this)'.
153 public bool ShapeRebuildScheduled { get; protected set; }
154
155 public override OMV.Vector3 Size {
156 get { return _size; }
157 set {
158 // We presume the scale and size are the same. If scale must be changed for
159 // the physical shape, that is done when the geometry is built.
160 _size = value;
161 Scale = _size;
162 ForceBodyShapeRebuild(false);
163 }
164 }
165
166 public override PrimitiveBaseShape Shape {
167 set {
168 BaseShape = value;
169 DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape));
170 PrimAssetState = PrimAssetCondition.Unknown;
171 ForceBodyShapeRebuild(false);
172 }
173 }
174 // Cause the body and shape of the prim to be rebuilt if necessary.
175 // If there are no changes required, this is quick and does not make changes to the prim.
176 // If rebuilding is necessary (like changing from static to physical), that will happen.
177 // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly.
178 // The return parameter is not used by anyone.
179 public override bool ForceBodyShapeRebuild(bool inTaintTime)
180 {
181 if (inTaintTime)
182 {
183 // If called in taint time, do the operation immediately
184 _mass = CalculateMass(); // changing the shape changes the mass
185 CreateGeomAndObject(true);
186 }
187 else
188 {
189 lock (this)
190 {
191 // If a rebuild is not already in the queue
192 if (!ShapeRebuildScheduled)
193 {
194 // Remember that a rebuild is queued -- this is used to flag an incomplete object
195 ShapeRebuildScheduled = true;
196 PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
197 {
198 _mass = CalculateMass(); // changing the shape changes the mass
199 CreateGeomAndObject(true);
200 ShapeRebuildScheduled = false;
201 });
202 }
203 }
204 }
205 return true;
206 }
207 public override bool Grabbed {
208 set { _grabbed = value;
209 }
210 }
211 public override bool Selected {
212 set
213 {
214 if (value != _isSelected)
215 {
216 _isSelected = value;
217 PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
218 {
219 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
220 SetObjectDynamic(false);
221 });
222 }
223 }
224 }
225 public override bool IsSelected
226 {
227 get { return _isSelected; }
228 }
229
230 public override void CrossingFailure()
231 {
232 CrossingFailures++;
233 if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
234 {
235 base.RaiseOutOfBounds(RawPosition);
236 }
237 else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
238 {
239 m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
240 }
241 return;
242 }
243
244 // link me to the specified parent
245 public override void link(PhysicsActor obj) {
246 }
247
248 // delink me from my linkset
249 public override void delink() {
250 }
251
252 // Set motion values to zero.
253 // Do it to the properties so the values get set in the physics engine.
254 // Push the setting of the values to the viewer.
255 // Called at taint time!
256 public override void ZeroMotion(bool inTaintTime)
257 {
258 RawVelocity = OMV.Vector3.Zero;
259 _acceleration = OMV.Vector3.Zero;
260 _rotationalVelocity = OMV.Vector3.Zero;
261
262 // Zero some other properties in the physics engine
263 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
264 {
265 if (PhysBody.HasPhysicalBody)
266 PhysScene.PE.ClearAllForces(PhysBody);
267 });
268 }
269 public override void ZeroAngularMotion(bool inTaintTime)
270 {
271 _rotationalVelocity = OMV.Vector3.Zero;
272 // Zero some other properties in the physics engine
273 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
274 {
275 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
276 if (PhysBody.HasPhysicalBody)
277 {
278 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
279 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
280 }
281 });
282 }
283
284 public override void LockAngularMotion(OMV.Vector3 axis)
285 {
286 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
287
288 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
289 if (axis.X != 1)
290 {
291 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f);
292 }
293 if (axis.Y != 1)
294 {
295 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f);
296 }
297 if (axis.Z != 1)
298 {
299 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f);
300 }
301
302 InitializeAxisActor();
303
304 return;
305 }
306
307 public override OMV.Vector3 Position {
308 get {
309 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
310 // RawPosition = ForcePosition;
311 return RawPosition;
312 }
313 set {
314 // If the position must be forced into the physics engine, use ForcePosition.
315 // All positions are given in world positions.
316 if (RawPosition == value)
317 {
318 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
319 return;
320 }
321 RawPosition = value;
322 PositionSanityCheck(false);
323
324 PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
325 {
326 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
327 ForcePosition = RawPosition;
328 });
329 }
330 }
331
332 // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity.
333 public override OMV.Vector3 ForcePosition {
334 get {
335 RawPosition = PhysScene.PE.GetPosition(PhysBody);
336 return RawPosition;
337 }
338 set {
339 RawPosition = value;
340 if (PhysBody.HasPhysicalBody)
341 {
342 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
343 ActivateIfPhysical(false);
344 }
345 }
346 }
347
348 // Check that the current position is sane and, if not, modify the position to make it so.
349 // Check for being below terrain and being out of bounds.
350 // Returns 'true' of the position was made sane by some action.
351 private bool PositionSanityCheck(bool inTaintTime)
352 {
353 bool ret = false;
354
355 // We don't care where non-physical items are placed
356 if (!IsPhysicallyActive)
357 return ret;
358
359 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
360 {
361 // The physical object is out of the known/simulated area.
362 // Upper levels of code will handle the transition to other areas so, for
363 // the time, we just ignore the position.
364 return ret;
365 }
366
367 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
368 OMV.Vector3 upForce = OMV.Vector3.Zero;
369 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
370 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
371 {
372 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
373 float targetHeight = terrainHeight + (Size.Z / 2f);
374 // If the object is below ground it just has to be moved up because pushing will
375 // not get it through the terrain
376 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight);
377 if (inTaintTime)
378 {
379 ForcePosition = RawPosition;
380 }
381 // If we are throwing the object around, zero its other forces
382 ZeroMotion(inTaintTime);
383 ret = true;
384 }
385
386 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
387 {
388 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
389 // TODO: a floating motor so object will bob in the water
390 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
391 {
392 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
393 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
394
395 // Apply upforce and overcome gravity.
396 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
397 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce);
398 AddForce(correctionForce, false, inTaintTime);
399 ret = true;
400 }
401 }
402
403 return ret;
404 }
405
406 // Occasionally things will fly off and really get lost.
407 // Find the wanderers and bring them back.
408 // Return 'true' if some parameter need some sanity.
409 private bool ExtremeSanityCheck(bool inTaintTime)
410 {
411 bool ret = false;
412
413 int wayOverThere = -1000;
414 int wayOutThere = 10000;
415 // There have been instances of objects getting thrown way out of bounds and crashing
416 // the border crossing code.
417 if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere
418 || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere
419 || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere)
420 {
421 RawPosition = new OMV.Vector3(10, 10, 50);
422 ZeroMotion(inTaintTime);
423 ret = true;
424 }
425 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared)
426 {
427 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
428 ret = true;
429 }
430 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
431 {
432 _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
433 ret = true;
434 }
435
436 return ret;
437 }
438
439 // Return the effective mass of the object.
440 // The definition of this call is to return the mass of the prim.
441 // If the simulator cares about the mass of the linkset, it will sum it itself.
442 public override float Mass
443 {
444 get { return _mass; }
445 }
446 // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
447 public virtual float TotalMass
448 {
449 get { return _mass; }
450 }
451 // used when we only want this prim's mass and not the linkset thing
452 public override float RawMass {
453 get { return _mass; }
454 }
455 // Set the physical mass to the passed mass.
456 // Note that this does not change _mass!
457 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
458 {
459 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
460 {
461 if (IsStatic)
462 {
463 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
464 Inertia = OMV.Vector3.Zero;
465 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
466 PhysScene.PE.UpdateInertiaTensor(PhysBody);
467 }
468 else
469 {
470 if (inWorld)
471 {
472 // Changing interesting properties doesn't change proxy and collision cache
473 // information. The Bullet solution is to re-add the object to the world
474 // after parameters are changed.
475 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
476 }
477
478 // The computation of mass props requires gravity to be set on the object.
479 Gravity = ComputeGravity(Buoyancy);
480 PhysScene.PE.SetGravity(PhysBody, Gravity);
481
482 // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
483 // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
484
485 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
486 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
487 PhysScene.PE.UpdateInertiaTensor(PhysBody);
488
489 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
490 LocalID, physMass, Inertia, Gravity, inWorld);
491
492 if (inWorld)
493 {
494 AddObjectToPhysicalWorld();
495 }
496 }
497 }
498 }
499
500 // Return what gravity should be set to this very moment
501 public OMV.Vector3 ComputeGravity(float buoyancy)
502 {
503 OMV.Vector3 ret = PhysScene.DefaultGravity;
504
505 if (!IsStatic)
506 {
507 ret *= (1f - buoyancy);
508 ret *= GravModifier;
509 }
510
511 return ret;
512 }
513
514 // Is this used?
515 public override OMV.Vector3 CenterOfMass
516 {
517 get { return RawPosition; }
518 }
519
520 // Is this used?
521 public override OMV.Vector3 GeometricCenter
522 {
523 get { return RawPosition; }
524 }
525
526 public override OMV.Vector3 Force {
527 get { return RawForce; }
528 set {
529 RawForce = value;
530 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
531 {
532 return new BSActorSetForce(PhysScene, this, SetForceActorName);
533 });
534
535 // Call update so actor Refresh() is called to start things off
536 PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate()
537 {
538 UpdatePhysicalParameters();
539 });
540 }
541 }
542
543 // Find and return a handle to the current vehicle actor.
544 // Return 'null' if there is no vehicle actor.
545 public BSDynamics GetVehicleActor(bool createIfNone)
546 {
547 BSDynamics ret = null;
548 BSActor actor;
549 if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
550 {
551 ret = actor as BSDynamics;
552 }
553 else
554 {
555 if (createIfNone)
556 {
557 ret = new BSDynamics(PhysScene, this, VehicleActorName);
558 PhysicalActors.Add(ret.ActorName, ret);
559 }
560 }
561 return ret;
562 }
563
564 public override int VehicleType {
565 get {
566 int ret = (int)Vehicle.TYPE_NONE;
567 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
568 if (vehicleActor != null)
569 ret = (int)vehicleActor.Type;
570 return ret;
571 }
572 set {
573 Vehicle type = (Vehicle)value;
574
575 PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
576 {
577 // Some vehicle scripts change vehicle type on the fly as an easy way to
578 // change all the parameters. Like a plane changing to CAR when on the
579 // ground. In this case, don't want to zero motion.
580 // ZeroMotion(true /* inTaintTime */);
581 if (type == Vehicle.TYPE_NONE)
582 {
583 // Vehicle type is 'none' so get rid of any actor that may have been allocated.
584 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
585 if (vehicleActor != null)
586 {
587 PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
588 }
589 }
590 else
591 {
592 // Vehicle type is not 'none' so create an actor and set it running.
593 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
594 if (vehicleActor != null)
595 {
596 vehicleActor.ProcessTypeChange(type);
597 ActivateIfPhysical(false);
598 }
599 }
600 });
601 }
602 }
603 public override void VehicleFloatParam(int param, float value)
604 {
605 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
606 {
607 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
608 if (vehicleActor != null)
609 {
610 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
611 ActivateIfPhysical(false);
612 }
613 });
614 }
615 public override void VehicleVectorParam(int param, OMV.Vector3 value)
616 {
617 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
618 {
619 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
620 if (vehicleActor != null)
621 {
622 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
623 ActivateIfPhysical(false);
624 }
625 });
626 }
627 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
628 {
629 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
630 {
631 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
632 if (vehicleActor != null)
633 {
634 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
635 ActivateIfPhysical(false);
636 }
637 });
638 }
639 public override void VehicleFlags(int param, bool remove)
640 {
641 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
642 {
643 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
644 if (vehicleActor != null)
645 {
646 vehicleActor.ProcessVehicleFlags(param, remove);
647 }
648 });
649 }
650
651 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
652 public override void SetVolumeDetect(int param) {
653 bool newValue = (param != 0);
654 if (_isVolumeDetect != newValue)
655 {
656 _isVolumeDetect = newValue;
657 PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
658 {
659 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
660 SetObjectDynamic(true);
661 });
662 }
663 return;
664 }
665 public override bool IsVolumeDetect
666 {
667 get { return _isVolumeDetect; }
668 }
669 public override void SetMaterial(int material)
670 {
671 base.SetMaterial(material);
672 PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
673 {
674 UpdatePhysicalParameters();
675 });
676 }
677 public override float Friction
678 {
679 get { return base.Friction; }
680 set
681 {
682 if (base.Friction != value)
683 {
684 base.Friction = value;
685 PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
686 {
687 UpdatePhysicalParameters();
688 });
689 }
690 }
691 }
692 public override float Restitution
693 {
694 get { return base.Restitution; }
695 set
696 {
697 if (base.Restitution != value)
698 {
699 base.Restitution = value;
700 PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
701 {
702 UpdatePhysicalParameters();
703 });
704 }
705 }
706 }
707 // The simulator/viewer keep density as 100kg/m3.
708 // Remember to use BSParam.DensityScaleFactor to create the physical density.
709 public override float Density
710 {
711 get { return base.Density; }
712 set
713 {
714 if (base.Density != value)
715 {
716 base.Density = value;
717 PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
718 {
719 UpdatePhysicalParameters();
720 });
721 }
722 }
723 }
724 public override float GravModifier
725 {
726 get { return base.GravModifier; }
727 set
728 {
729 if (base.GravModifier != value)
730 {
731 base.GravModifier = value;
732 PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
733 {
734 UpdatePhysicalParameters();
735 });
736 }
737 }
738 }
739 public override OMV.Vector3 Velocity {
740 get { return RawVelocity; }
741 set {
742 RawVelocity = value;
743 PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
744 {
745 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
746 ForceVelocity = RawVelocity;
747 });
748 }
749 }
750 public override OMV.Vector3 ForceVelocity {
751 get { return RawVelocity; }
752 set {
753 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
754
755 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
756 if (PhysBody.HasPhysicalBody)
757 {
758 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
759 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
760 ActivateIfPhysical(false);
761 }
762 }
763 }
764 public override OMV.Vector3 Torque {
765 get { return RawTorque; }
766 set {
767 RawTorque = value;
768 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
769 {
770 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
771 });
772 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
773
774 // Call update so actor Refresh() is called to start things off
775 PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate()
776 {
777 UpdatePhysicalParameters();
778 });
779 }
780 }
781 public override OMV.Vector3 Acceleration {
782 get { return _acceleration; }
783 set { _acceleration = value; }
784 }
785
786 public override OMV.Quaternion Orientation {
787 get {
788 return RawOrientation;
789 }
790 set {
791 if (RawOrientation == value)
792 return;
793 RawOrientation = value;
794
795 PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
796 {
797 ForceOrientation = RawOrientation;
798 });
799 }
800 }
801 // Go directly to Bullet to get/set the value.
802 public override OMV.Quaternion ForceOrientation
803 {
804 get
805 {
806 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
807 return RawOrientation;
808 }
809 set
810 {
811 RawOrientation = value;
812 if (PhysBody.HasPhysicalBody)
813 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
814 }
815 }
816 public override int PhysicsActorType {
817 get { return _physicsActorType; }
818 set { _physicsActorType = value; }
819 }
820 public override bool IsPhysical {
821 get { return _isPhysical; }
822 set {
823 if (_isPhysical != value)
824 {
825 _isPhysical = value;
826 PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
827 {
828 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
829 SetObjectDynamic(true);
830 // whether phys-to-static or static-to-phys, the object is not moving.
831 ZeroMotion(true);
832
833 });
834 }
835 }
836 }
837
838 // An object is static (does not move) if selected or not physical
839 public override bool IsStatic
840 {
841 get { return _isSelected || !IsPhysical; }
842 }
843
844 // An object is solid if it's not phantom and if it's not doing VolumeDetect
845 public override bool IsSolid
846 {
847 get { return !IsPhantom && !_isVolumeDetect; }
848 }
849
850 // The object is moving and is actively being dynamic in the physical world
851 public override bool IsPhysicallyActive
852 {
853 get { return !_isSelected && IsPhysical; }
854 }
855
856 // Make gravity work if the object is physical and not selected
857 // Called at taint-time!!
858 private void SetObjectDynamic(bool forceRebuild)
859 {
860 // Recreate the physical object if necessary
861 CreateGeomAndObject(forceRebuild);
862 }
863
864 // Convert the simulator's physical properties into settings on BulletSim objects.
865 // There are four flags we're interested in:
866 // IsStatic: Object does not move, otherwise the object has mass and moves
867 // isSolid: other objects bounce off of this object
868 // isVolumeDetect: other objects pass through but can generate collisions
869 // collisionEvents: whether this object returns collision events
870 // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
871 public virtual void UpdatePhysicalParameters()
872 {
873 if (!PhysBody.HasPhysicalBody)
874 {
875 // This would only happen if updates are called for during initialization when the body is not set up yet.
876 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
877 return;
878 }
879
880 // Mangling all the physical properties requires the object not be in the physical world.
881 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
882 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
883
884 // Set up the object physicalness (does gravity and collisions move this object)
885 MakeDynamic(IsStatic);
886
887 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
888 PhysicalActors.Refresh();
889
890 // Arrange for collision events if the simulator wants them
891 EnableCollisions(SubscribedEvents());
892
893 // Make solid or not (do things bounce off or pass through this object).
894 MakeSolid(IsSolid);
895
896 AddObjectToPhysicalWorld();
897
898 // Rebuild its shape
899 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
900
901 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
902 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
903 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
904 }
905
906 // "Making dynamic" means changing to and from static.
907 // When static, gravity does not effect the object and it is fixed in space.
908 // When dynamic, the object can fall and be pushed by others.
909 // This is independent of its 'solidness' which controls what passes through
910 // this object and what interacts with it.
911 protected virtual void MakeDynamic(bool makeStatic)
912 {
913 if (makeStatic)
914 {
915 // Become a Bullet 'static' object type
916 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
917 // Stop all movement
918 ZeroMotion(true);
919
920 // Set various physical properties so other object interact properly
921 PhysScene.PE.SetFriction(PhysBody, Friction);
922 PhysScene.PE.SetRestitution(PhysBody, Restitution);
923 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
924
925 // Mass is zero which disables a bunch of physics stuff in Bullet
926 UpdatePhysicalMassProperties(0f, false);
927 // Set collision detection parameters
928 if (BSParam.CcdMotionThreshold > 0f)
929 {
930 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
931 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
932 }
933
934 // The activation state is 'disabled' so Bullet will not try to act on it.
935 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
936 // Start it out sleeping and physical actions could wake it up.
937 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
938
939 // This collides like a static object
940 PhysBody.collisionType = CollisionType.Static;
941 }
942 else
943 {
944 // Not a Bullet static object
945 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
946
947 // Set various physical properties so other object interact properly
948 PhysScene.PE.SetFriction(PhysBody, Friction);
949 PhysScene.PE.SetRestitution(PhysBody, Restitution);
950 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
951
952 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
953 // Since this can be called multiple times, only zero forces when becoming physical
954 // PhysicsScene.PE.ClearAllForces(BSBody);
955
956 // For good measure, make sure the transform is set through to the motion state
957 ForcePosition = RawPosition;
958 ForceVelocity = RawVelocity;
959 ForceRotationalVelocity = _rotationalVelocity;
960
961 // A dynamic object has mass
962 UpdatePhysicalMassProperties(RawMass, false);
963
964 // Set collision detection parameters
965 if (BSParam.CcdMotionThreshold > 0f)
966 {
967 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
968 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
969 }
970
971 // Various values for simulation limits
972 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
973 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
974 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
975 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
976
977 // This collides like an object.
978 PhysBody.collisionType = CollisionType.Dynamic;
979
980 // Force activation of the object so Bullet will act on it.
981 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
982 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
983 }
984 }
985
986 // "Making solid" means that other object will not pass through this object.
987 // To make transparent, we create a Bullet ghost object.
988 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
989 // the functions after this one set up the state of a possibly newly created collision body.
990 private void MakeSolid(bool makeSolid)
991 {
992 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
993 if (makeSolid)
994 {
995 // Verify the previous code created the correct shape for this type of thing.
996 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
997 {
998 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
999 }
1000 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1001 }
1002 else
1003 {
1004 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
1005 {
1006 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
1007 }
1008 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1009
1010 // Change collision info from a static object to a ghosty collision object
1011 PhysBody.collisionType = CollisionType.VolumeDetect;
1012 }
1013 }
1014
1015 // Turn on or off the flag controlling whether collision events are returned to the simulator.
1016 private void EnableCollisions(bool wantsCollisionEvents)
1017 {
1018 if (wantsCollisionEvents)
1019 {
1020 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1021 }
1022 else
1023 {
1024 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1025 }
1026 }
1027
1028 // Add me to the physical world.
1029 // Object MUST NOT already be in the world.
1030 // This routine exists because some assorted properties get mangled by adding to the world.
1031 internal void AddObjectToPhysicalWorld()
1032 {
1033 if (PhysBody.HasPhysicalBody)
1034 {
1035 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
1036 }
1037 else
1038 {
1039 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
1040 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
1041 }
1042 }
1043
1044 // prims don't fly
1045 public override bool Flying {
1046 get { return _flying; }
1047 set {
1048 _flying = value;
1049 }
1050 }
1051 public override bool SetAlwaysRun {
1052 get { return _setAlwaysRun; }
1053 set { _setAlwaysRun = value; }
1054 }
1055 public override bool ThrottleUpdates {
1056 get { return _throttleUpdates; }
1057 set { _throttleUpdates = value; }
1058 }
1059 public bool IsPhantom {
1060 get {
1061 // SceneObjectPart removes phantom objects from the physics scene
1062 // so, although we could implement touching and such, we never
1063 // are invoked as a phantom object
1064 return false;
1065 }
1066 }
1067 public override bool FloatOnWater {
1068 set {
1069 _floatOnWater = value;
1070 PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1071 {
1072 if (_floatOnWater)
1073 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1074 else
1075 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1076 });
1077 }
1078 }
1079 public override OMV.Vector3 RotationalVelocity {
1080 get {
1081 return _rotationalVelocity;
1082 }
1083 set {
1084 _rotationalVelocity = value;
1085 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1086 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1087 PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1088 {
1089 ForceRotationalVelocity = _rotationalVelocity;
1090 });
1091 }
1092 }
1093 public override OMV.Vector3 ForceRotationalVelocity {
1094 get {
1095 return _rotationalVelocity;
1096 }
1097 set {
1098 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
1099 if (PhysBody.HasPhysicalBody)
1100 {
1101 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1102 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1103 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1104 ActivateIfPhysical(false);
1105 }
1106 }
1107 }
1108 public override bool Kinematic {
1109 get { return _kinematic; }
1110 set { _kinematic = value;
1111 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
1112 }
1113 }
1114 public override float Buoyancy {
1115 get { return _buoyancy; }
1116 set {
1117 _buoyancy = value;
1118 PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1119 {
1120 ForceBuoyancy = _buoyancy;
1121 });
1122 }
1123 }
1124 public override float ForceBuoyancy {
1125 get { return _buoyancy; }
1126 set {
1127 _buoyancy = value;
1128 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
1129 // Force the recalculation of the various inertia,etc variables in the object
1130 UpdatePhysicalMassProperties(RawMass, true);
1131 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1132 ActivateIfPhysical(false);
1133 }
1134 }
1135
1136 public override bool PIDActive
1137 {
1138 get
1139 {
1140 return MoveToTargetActive;
1141 }
1142
1143 set
1144 {
1145 MoveToTargetActive = value;
1146
1147 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1148 {
1149 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1150 });
1151
1152 // Call update so actor Refresh() is called to start things off
1153 PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate()
1154 {
1155 UpdatePhysicalParameters();
1156 });
1157 }
1158 }
1159
1160 public override OMV.Vector3 PIDTarget
1161 {
1162 set
1163 {
1164 base.PIDTarget = value;
1165 BSActor actor;
1166 if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1167 {
1168 // if the actor exists, tell it to refresh its values.
1169 actor.Refresh();
1170 }
1171
1172 }
1173 }
1174 // Used for llSetHoverHeight and maybe vehicle height
1175 // Hover Height will override MoveTo target's Z
1176 public override bool PIDHoverActive {
1177 set {
1178 base.HoverActive = value;
1179 EnableActor(HoverActive, HoverActorName, delegate()
1180 {
1181 return new BSActorHover(PhysScene, this, HoverActorName);
1182 });
1183
1184 // Call update so actor Refresh() is called to start things off
1185 PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate()
1186 {
1187 UpdatePhysicalParameters();
1188 });
1189 }
1190 }
1191
1192 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1193 // Per documentation, max force is limited.
1194 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1195
1196 // Since this force is being applied in only one step, make this a force per second.
1197 addForce /= PhysScene.LastTimeStep;
1198 AddForce(addForce, pushforce, false /* inTaintTime */);
1199 }
1200
1201 // Applying a force just adds this to the total force on the object.
1202 // This added force will only last the next simulation tick.
1203 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1204 // for an object, doesn't matter if force is a pushforce or not
1205 if (IsPhysicallyActive)
1206 {
1207 if (force.IsFinite())
1208 {
1209 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1210
1211 OMV.Vector3 addForce = force;
1212 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1213 {
1214 // Bullet adds this central force to the total force for this tick.
1215 // Deep down in Bullet:
1216 // linearVelocity += totalForce / mass * timeStep;
1217 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1218 if (PhysBody.HasPhysicalBody)
1219 {
1220 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1221 ActivateIfPhysical(false);
1222 }
1223 });
1224 }
1225 else
1226 {
1227 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1228 return;
1229 }
1230 }
1231 }
1232
1233 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
1234 // for an object, doesn't matter if force is a pushforce or not
1235 if (!IsPhysicallyActive)
1236 {
1237 if (impulse.IsFinite())
1238 {
1239 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1240 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1241
1242 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1243 {
1244 // Bullet adds this impulse immediately to the velocity
1245 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1246 if (PhysBody.HasPhysicalBody)
1247 {
1248 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1249 ActivateIfPhysical(false);
1250 }
1251 });
1252 }
1253 else
1254 {
1255 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1256 return;
1257 }
1258 }
1259 }
1260
1261 // BSPhysObject.AddAngularForce()
1262 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1263 {
1264 if (force.IsFinite())
1265 {
1266 OMV.Vector3 angForce = force;
1267 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1268 {
1269 if (PhysBody.HasPhysicalBody)
1270 {
1271 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1272 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1273 ActivateIfPhysical(false);
1274 }
1275 });
1276 }
1277 else
1278 {
1279 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1280 return;
1281 }
1282 }
1283
1284 // A torque impulse.
1285 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1286 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1287 // Computed as: angularVelocity += impulse * inertia;
1288 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1289 {
1290 OMV.Vector3 applyImpulse = impulse;
1291 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1292 {
1293 if (PhysBody.HasPhysicalBody)
1294 {
1295 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1296 ActivateIfPhysical(false);
1297 }
1298 });
1299 }
1300
1301 public override void SetMomentum(OMV.Vector3 momentum) {
1302 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1303 }
1304 #region Mass Calculation
1305
1306 private float CalculateMass()
1307 {
1308 float volume = _size.X * _size.Y * _size.Z; // default
1309 float tmp;
1310
1311 float returnMass = 0;
1312 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1313 float hollowVolume = hollowAmount * hollowAmount;
1314
1315 switch (BaseShape.ProfileShape)
1316 {
1317 case ProfileShape.Square:
1318 // default box
1319
1320 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1321 {
1322 if (hollowAmount > 0.0)
1323 {
1324 switch (BaseShape.HollowShape)
1325 {
1326 case HollowShape.Square:
1327 case HollowShape.Same:
1328 break;
1329
1330 case HollowShape.Circle:
1331
1332 hollowVolume *= 0.78539816339f;
1333 break;
1334
1335 case HollowShape.Triangle:
1336
1337 hollowVolume *= (0.5f * .5f);
1338 break;
1339
1340 default:
1341 hollowVolume = 0;
1342 break;
1343 }
1344 volume *= (1.0f - hollowVolume);
1345 }
1346 }
1347
1348 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1349 {
1350 //a tube
1351
1352 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1353 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1354 volume -= volume*tmp*tmp;
1355
1356 if (hollowAmount > 0.0)
1357 {
1358 hollowVolume *= hollowAmount;
1359
1360 switch (BaseShape.HollowShape)
1361 {
1362 case HollowShape.Square:
1363 case HollowShape.Same:
1364 break;
1365
1366 case HollowShape.Circle:
1367 hollowVolume *= 0.78539816339f;;
1368 break;
1369
1370 case HollowShape.Triangle:
1371 hollowVolume *= 0.5f * 0.5f;
1372 break;
1373 default:
1374 hollowVolume = 0;
1375 break;
1376 }
1377 volume *= (1.0f - hollowVolume);
1378 }
1379 }
1380
1381 break;
1382
1383 case ProfileShape.Circle:
1384
1385 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1386 {
1387 volume *= 0.78539816339f; // elipse base
1388
1389 if (hollowAmount > 0.0)
1390 {
1391 switch (BaseShape.HollowShape)
1392 {
1393 case HollowShape.Same:
1394 case HollowShape.Circle:
1395 break;
1396
1397 case HollowShape.Square:
1398 hollowVolume *= 0.5f * 2.5984480504799f;
1399 break;
1400
1401 case HollowShape.Triangle:
1402 hollowVolume *= .5f * 1.27323954473516f;
1403 break;
1404
1405 default:
1406 hollowVolume = 0;
1407 break;
1408 }
1409 volume *= (1.0f - hollowVolume);
1410 }
1411 }
1412
1413 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1414 {
1415 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1416 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1417 volume *= (1.0f - tmp * tmp);
1418
1419 if (hollowAmount > 0.0)
1420 {
1421
1422 // calculate the hollow volume by it's shape compared to the prim shape
1423 hollowVolume *= hollowAmount;
1424
1425 switch (BaseShape.HollowShape)
1426 {
1427 case HollowShape.Same:
1428 case HollowShape.Circle:
1429 break;
1430
1431 case HollowShape.Square:
1432 hollowVolume *= 0.5f * 2.5984480504799f;
1433 break;
1434
1435 case HollowShape.Triangle:
1436 hollowVolume *= .5f * 1.27323954473516f;
1437 break;
1438
1439 default:
1440 hollowVolume = 0;
1441 break;
1442 }
1443 volume *= (1.0f - hollowVolume);
1444 }
1445 }
1446 break;
1447
1448 case ProfileShape.HalfCircle:
1449 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1450 {
1451 volume *= 0.52359877559829887307710723054658f;
1452 }
1453 break;
1454
1455 case ProfileShape.EquilateralTriangle:
1456
1457 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1458 {
1459 volume *= 0.32475953f;
1460
1461 if (hollowAmount > 0.0)
1462 {
1463
1464 // calculate the hollow volume by it's shape compared to the prim shape
1465 switch (BaseShape.HollowShape)
1466 {
1467 case HollowShape.Same:
1468 case HollowShape.Triangle:
1469 hollowVolume *= .25f;
1470 break;
1471
1472 case HollowShape.Square:
1473 hollowVolume *= 0.499849f * 3.07920140172638f;
1474 break;
1475
1476 case HollowShape.Circle:
1477 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1478 // Cyllinder hollow volume calculation
1479
1480 hollowVolume *= 0.1963495f * 3.07920140172638f;
1481 break;
1482
1483 default:
1484 hollowVolume = 0;
1485 break;
1486 }
1487 volume *= (1.0f - hollowVolume);
1488 }
1489 }
1490 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1491 {
1492 volume *= 0.32475953f;
1493 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1494 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1495 volume *= (1.0f - tmp * tmp);
1496
1497 if (hollowAmount > 0.0)
1498 {
1499
1500 hollowVolume *= hollowAmount;
1501
1502 switch (BaseShape.HollowShape)
1503 {
1504 case HollowShape.Same:
1505 case HollowShape.Triangle:
1506 hollowVolume *= .25f;
1507 break;
1508
1509 case HollowShape.Square:
1510 hollowVolume *= 0.499849f * 3.07920140172638f;
1511 break;
1512
1513 case HollowShape.Circle:
1514
1515 hollowVolume *= 0.1963495f * 3.07920140172638f;
1516 break;
1517
1518 default:
1519 hollowVolume = 0;
1520 break;
1521 }
1522 volume *= (1.0f - hollowVolume);
1523 }
1524 }
1525 break;
1526
1527 default:
1528 break;
1529 }
1530
1531
1532
1533 float taperX1;
1534 float taperY1;
1535 float taperX;
1536 float taperY;
1537 float pathBegin;
1538 float pathEnd;
1539 float profileBegin;
1540 float profileEnd;
1541
1542 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1543 {
1544 taperX1 = BaseShape.PathScaleX * 0.01f;
1545 if (taperX1 > 1.0f)
1546 taperX1 = 2.0f - taperX1;
1547 taperX = 1.0f - taperX1;
1548
1549 taperY1 = BaseShape.PathScaleY * 0.01f;
1550 if (taperY1 > 1.0f)
1551 taperY1 = 2.0f - taperY1;
1552 taperY = 1.0f - taperY1;
1553 }
1554 else
1555 {
1556 taperX = BaseShape.PathTaperX * 0.01f;
1557 if (taperX < 0.0f)
1558 taperX = -taperX;
1559 taperX1 = 1.0f - taperX;
1560
1561 taperY = BaseShape.PathTaperY * 0.01f;
1562 if (taperY < 0.0f)
1563 taperY = -taperY;
1564 taperY1 = 1.0f - taperY;
1565
1566 }
1567
1568
1569 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1570
1571 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1572 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1573 volume *= (pathEnd - pathBegin);
1574
1575 // this is crude aproximation
1576 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1577 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1578 volume *= (profileEnd - profileBegin);
1579
1580 returnMass = Density * BSParam.DensityScaleFactor * volume;
1581
1582 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1583 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1584 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1585 LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1586
1587 return returnMass;
1588 }// end CalculateMass
1589 #endregion Mass Calculation
1590
1591 // Rebuild the geometry and object.
1592 // This is called when the shape changes so we need to recreate the mesh/hull.
1593 // Called at taint-time!!!
1594 public void CreateGeomAndObject(bool forceRebuild)
1595 {
1596 // Create the correct physical representation for this type of object.
1597 // Updates base.PhysBody and base.PhysShape with the new information.
1598 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1599 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1600 {
1601 // Called if the current prim body is about to be destroyed.
1602 // Remove all the physical dependencies on the old body.
1603 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1604 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1605 RemoveDependencies();
1606 });
1607
1608 // Make sure the properties are set on the new object
1609 UpdatePhysicalParameters();
1610 return;
1611 }
1612
1613 // Called at taint-time
1614 protected virtual void RemoveDependencies()
1615 {
1616 PhysicalActors.RemoveDependencies();
1617 }
1618
1619 #region Extension
1620 public override object Extension(string pFunct, params object[] pParams)
1621 {
1622 DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1623 object ret = null;
1624 switch (pFunct)
1625 {
1626 case ExtendedPhysics.PhysFunctAxisLockLimits:
1627 ret = SetAxisLockLimitsExtension(pParams);
1628 break;
1629 default:
1630 ret = base.Extension(pFunct, pParams);
1631 break;
1632 }
1633 return ret;
1634 }
1635
1636 private void InitializeAxisActor()
1637 {
1638 EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree,
1639 LockedAxisActorName, delegate()
1640 {
1641 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
1642 });
1643
1644 // Update parameters so the new actor's Refresh() action is called at the right time.
1645 PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate()
1646 {
1647 UpdatePhysicalParameters();
1648 });
1649 }
1650
1651 // Passed an array of an array of parameters, set the axis locking.
1652 // This expects an int (PHYS_AXIS_*) followed by none or two limit floats
1653 // followed by another int and floats, etc.
1654 private object SetAxisLockLimitsExtension(object[] pParams)
1655 {
1656 DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0));
1657 object ret = null;
1658 try
1659 {
1660 if (pParams.GetLength(0) > 1)
1661 {
1662 int index = 2;
1663 while (index < pParams.GetLength(0))
1664 {
1665 var funct = pParams[index];
1666 DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index);
1667 if (funct is Int32 || funct is Int64)
1668 {
1669 switch ((int)funct)
1670 {
1671 // Those that take no parameters
1672 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1673 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1674 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1675 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1676 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1677 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1678 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1679 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1680 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1681 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1682 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1683 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1684 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1685 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1686 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1687 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1688 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1689 ApplyAxisLimits((int)funct, 0f, 0f);
1690 index += 1;
1691 break;
1692 // Those that take two parameters (the limits)
1693 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1694 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1695 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1696 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1697 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1698 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1699 ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]);
1700 index += 3;
1701 break;
1702 default:
1703 m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct);
1704 index += 1;
1705 break;
1706 }
1707 }
1708 }
1709 InitializeAxisActor();
1710 ret = (object)index;
1711 }
1712 }
1713 catch (Exception e)
1714 {
1715 m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e);
1716 ret = null;
1717 }
1718 return ret; // not implemented yet
1719 }
1720
1721 // Set the locking parameters.
1722 // If an axis is locked, the limits for the axis are set to zero,
1723 // If the axis is being constrained, the high and low value are passed and set.
1724 // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range.
1725 protected void ApplyAxisLimits(int funct, float low, float high)
1726 {
1727 DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high);
1728 float linearMax = 23000f;
1729 float angularMax = (float)Math.PI;
1730
1731 switch (funct)
1732 {
1733 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1734 this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1735 this.LockedLinearAxisLow = OMV.Vector3.Zero;
1736 this.LockedLinearAxisHigh = OMV.Vector3.Zero;
1737 break;
1738 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1739 this.LockedLinearAxis.X = LockedAxis;
1740 this.LockedLinearAxisLow.X = 0f;
1741 this.LockedLinearAxisHigh.X = 0f;
1742 break;
1743 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1744 this.LockedLinearAxis.X = LockedAxis;
1745 this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax);
1746 this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax);
1747 break;
1748 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1749 this.LockedLinearAxis.Y = LockedAxis;
1750 this.LockedLinearAxisLow.Y = 0f;
1751 this.LockedLinearAxisHigh.Y = 0f;
1752 break;
1753 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1754 this.LockedLinearAxis.Y = LockedAxis;
1755 this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax);
1756 this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax);
1757 break;
1758 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1759 this.LockedLinearAxis.Z = LockedAxis;
1760 this.LockedLinearAxisLow.Z = 0f;
1761 this.LockedLinearAxisHigh.Z = 0f;
1762 break;
1763 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1764 this.LockedLinearAxis.Z = LockedAxis;
1765 this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax);
1766 this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax);
1767 break;
1768 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1769 this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1770 this.LockedAngularAxisLow = OMV.Vector3.Zero;
1771 this.LockedAngularAxisHigh = OMV.Vector3.Zero;
1772 break;
1773 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1774 this.LockedAngularAxis.X = LockedAxis;
1775 this.LockedAngularAxisLow.X = 0;
1776 this.LockedAngularAxisHigh.X = 0;
1777 break;
1778 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1779 this.LockedAngularAxis.X = LockedAxis;
1780 this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax);
1781 this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax);
1782 break;
1783 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1784 this.LockedAngularAxis.Y = LockedAxis;
1785 this.LockedAngularAxisLow.Y = 0;
1786 this.LockedAngularAxisHigh.Y = 0;
1787 break;
1788 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1789 this.LockedAngularAxis.Y = LockedAxis;
1790 this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax);
1791 this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax);
1792 break;
1793 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1794 this.LockedAngularAxis.Z = LockedAxis;
1795 this.LockedAngularAxisLow.Z = 0;
1796 this.LockedAngularAxisHigh.Z = 0;
1797 break;
1798 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1799 this.LockedAngularAxis.Z = LockedAxis;
1800 this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax);
1801 this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax);
1802 break;
1803 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1804 this.LockedLinearAxis = LockedAxisFree;
1805 this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax);
1806 this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax);
1807 break;
1808 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1809 this.LockedLinearAxis.X = FreeAxis;
1810 this.LockedLinearAxisLow.X = -linearMax;
1811 this.LockedLinearAxisHigh.X = linearMax;
1812 break;
1813 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1814 this.LockedLinearAxis.Y = FreeAxis;
1815 this.LockedLinearAxisLow.Y = -linearMax;
1816 this.LockedLinearAxisHigh.Y = linearMax;
1817 break;
1818 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1819 this.LockedLinearAxis.Z = FreeAxis;
1820 this.LockedLinearAxisLow.Z = -linearMax;
1821 this.LockedLinearAxisHigh.Z = linearMax;
1822 break;
1823 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1824 this.LockedAngularAxis = LockedAxisFree;
1825 this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax);
1826 this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax);
1827 break;
1828 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1829 this.LockedAngularAxis.X = FreeAxis;
1830 this.LockedAngularAxisLow.X = -angularMax;
1831 this.LockedAngularAxisHigh.X = angularMax;
1832 break;
1833 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1834 this.LockedAngularAxis.Y = FreeAxis;
1835 this.LockedAngularAxisLow.Y = -angularMax;
1836 this.LockedAngularAxisHigh.Y = angularMax;
1837 break;
1838 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1839 this.LockedAngularAxis.Z = FreeAxis;
1840 this.LockedAngularAxisLow.Z = -angularMax;
1841 this.LockedAngularAxisHigh.Z = angularMax;
1842 break;
1843 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1844 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f);
1845 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
1846 break;
1847 default:
1848 break;
1849 }
1850 return;
1851 }
1852 #endregion // Extension
1853
1854 // The physics engine says that properties have updated. Update same and inform
1855 // the world that things have changed.
1856 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1857 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1858 public override void UpdateProperties(EntityProperties entprop)
1859 {
1860 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1861 TriggerPreUpdatePropertyAction(ref entprop);
1862
1863 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1864
1865 // Assign directly to the local variables so the normal set actions do not happen
1866 RawPosition = entprop.Position;
1867 RawOrientation = entprop.Rotation;
1868 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1869 // very sensitive to velocity changes.
1870 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1871 RawVelocity = entprop.Velocity;
1872 _acceleration = entprop.Acceleration;
1873 _rotationalVelocity = entprop.RotationalVelocity;
1874
1875 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1876
1877 // The sanity check can change the velocity and/or position.
1878 if (PositionSanityCheck(true /* inTaintTime */ ))
1879 {
1880 entprop.Position = RawPosition;
1881 entprop.Velocity = RawVelocity;
1882 entprop.RotationalVelocity = _rotationalVelocity;
1883 entprop.Acceleration = _acceleration;
1884 }
1885
1886 OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1887 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1888
1889 // remember the current and last set values
1890 LastEntityProperties = CurrentEntityProperties;
1891 CurrentEntityProperties = entprop;
1892
1893 PhysScene.PostUpdate(this);
1894 }
1895}
1896}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
new file mode 100755
index 0000000..2eb1440
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
@@ -0,0 +1,182 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35
36using OMV = OpenMetaverse;
37
38namespace OpenSim.Region.Physics.BulletSPlugin
39{
40public class BSPrimDisplaced : BSPrim
41{
42 // The purpose of this subclass is to do any mapping between what the simulator thinks
43 // the prim position and orientation is and what the physical position/orientation.
44 // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
45 // of the prim/linkset. The simulator, on the other hand, tracks the location of
46 // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere
47 // but the origin of the root prim, the physical origin is displaced from the simulator origin.
48 //
49 // This routine works by capturing ForcePosition and
50 // adjusting the simulator values (being set) into the physical values.
51 // The conversion is also done in the opposite direction (physical origin -> simulator origin).
52 //
53 // The updateParameter call is also captured and the values from the physics engine
54 // are converted into simulator origin values before being passed to the base
55 // class.
56
57 // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass.
58 public virtual OMV.Vector3 PositionDisplacement { get; set; }
59
60 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
61 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
62 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
63 {
64 ClearDisplacement();
65 }
66
67 // Clears any center-of-mass displacement introduced by linksets, etc.
68 // Does not clear the displacement set by the user.
69 public void ClearDisplacement()
70 {
71 if (UserSetCenterOfMassDisplacement.HasValue)
72 PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement;
73 else
74 PositionDisplacement = OMV.Vector3.Zero;
75 }
76
77 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
78 // A user set value for center-of-mass overrides whatever might be passed in here.
79 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
80 // Returns the relative offset from the root position to the center-of-mass.
81 // Called at taint time.
82 public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
83 {
84 PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement");
85 Vector3 comDisp;
86 if (UserSetCenterOfMassDisplacement.HasValue)
87 comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
88 else
89 comDisp = centerOfMassDisplacement;
90
91 // Eliminate any jitter caused be very slight differences in masses and positions
92 if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) )
93 comDisp = Vector3.Zero;
94
95 DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}",
96 LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp);
97 if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) )
98 {
99 // Displacement setting is changing.
100 // The relationship between the physical object and simulated object must be aligned.
101 PositionDisplacement = comDisp;
102 this.ForcePosition = RawPosition;
103 }
104
105 return PositionDisplacement;
106 }
107
108 // 'ForcePosition' is the one way to set the physical position of the body in the physics engine.
109 // Displace the simulator idea of position (center of root prim) to the physical position.
110 public override Vector3 ForcePosition
111 {
112 get {
113 OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody);
114 if (PositionDisplacement != OMV.Vector3.Zero)
115 {
116 // If there is some displacement, return the physical position (center-of-mass)
117 // location minus the displacement to give the center of the root prim.
118 OMV.Vector3 displacement = PositionDisplacement * ForceOrientation;
119 DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}",
120 LocalID, physPosition, displacement, physPosition - displacement);
121 physPosition -= displacement;
122 }
123 RawPosition = physPosition;
124 return physPosition;
125 }
126 set
127 {
128 if (PositionDisplacement != OMV.Vector3.Zero)
129 {
130 // This value is the simulator's idea of where the prim is: the center of the root prim
131 RawPosition = value;
132
133 // Move the passed root prim postion to the center-of-mass position and set in the physics engine.
134 OMV.Vector3 displacement = PositionDisplacement * RawOrientation;
135 OMV.Vector3 displacedPos = RawPosition + displacement;
136 DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}",
137 LocalID, RawPosition, displacement, displacedPos);
138 if (PhysBody.HasPhysicalBody)
139 {
140 PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation);
141 ActivateIfPhysical(false);
142 }
143 }
144 else
145 {
146 base.ForcePosition = value;
147 }
148 }
149 }
150
151 // These are also overridden by BSPrimLinkable if the prim can be part of a linkset
152 public override OMV.Vector3 CenterOfMass
153 {
154 get { return RawPosition; }
155 }
156
157 public override OMV.Vector3 GeometricCenter
158 {
159 get { return RawPosition; }
160 }
161
162 public override void UpdateProperties(EntityProperties entprop)
163 {
164 // Undo any center-of-mass displacement that might have been done.
165 if (PositionDisplacement != OMV.Vector3.Zero)
166 {
167 // The origional shape was offset from 'zero' by PositionDisplacement.
168 // These physical location must be back converted to be centered around the displaced
169 // root shape.
170
171 // Move the returned center-of-mass location to the root prim location.
172 OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation;
173 OMV.Vector3 displacedPos = entprop.Position - displacement;
174 DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}",
175 LocalID, entprop.Position, displacement, displacedPos);
176 entprop.Position = displacedPos;
177 }
178
179 base.UpdateProperties(entprop);
180 }
181}
182}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
new file mode 100755
index 0000000..430d645
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
@@ -0,0 +1,350 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Linq;
30using System.Text;
31
32using OpenSim.Framework;
33using OpenSim.Region.OptionalModules.Scripting;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSPrimLinkable : BSPrimDisplaced
40{
41 // The purpose of this subclass is to add linkset functionality to the prim. This overrides
42 // operations necessary for keeping the linkset created and, additionally, this
43 // calls the linkset implementation for its creation and management.
44
45#pragma warning disable 414
46 private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]";
47#pragma warning restore 414
48
49 // This adds the overrides for link() and delink() so the prim is linkable.
50
51 public BSLinkset Linkset { get; set; }
52 // The index of this child prim.
53 public int LinksetChildIndex { get; set; }
54
55 public BSLinkset.LinksetImplementation LinksetType { get; set; }
56
57 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
58 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
59 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
60 {
61 // Default linkset implementation for this prim
62 LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation;
63
64 Linkset = BSLinkset.Factory(PhysScene, this);
65
66 Linkset.Refresh(this);
67 }
68
69 public override void Destroy()
70 {
71 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */);
72 base.Destroy();
73 }
74
75 public override void link(Manager.PhysicsActor obj)
76 {
77 BSPrimLinkable parent = obj as BSPrimLinkable;
78 if (parent != null)
79 {
80 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
81 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
82
83 Linkset = parent.Linkset.AddMeToLinkset(this);
84
85 DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
86 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
87 }
88 return;
89 }
90
91 public override void delink()
92 {
93 // TODO: decide if this parent checking needs to happen at taint time
94 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
95
96 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
97 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
98
99 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/);
100
101 DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
102 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
103 return;
104 }
105
106 // When simulator changes position, this might be moving a child of the linkset.
107 public override OMV.Vector3 Position
108 {
109 get { return base.Position; }
110 set
111 {
112 base.Position = value;
113 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate()
114 {
115 Linkset.UpdateProperties(UpdatedProperties.Position, this);
116 });
117 }
118 }
119
120 // When simulator changes orientation, this might be moving a child of the linkset.
121 public override OMV.Quaternion Orientation
122 {
123 get { return base.Orientation; }
124 set
125 {
126 base.Orientation = value;
127 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate()
128 {
129 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
130 });
131 }
132 }
133
134 public override float TotalMass
135 {
136 get { return Linkset.LinksetMass; }
137 }
138
139 public override OMV.Vector3 CenterOfMass
140 {
141 get { return Linkset.CenterOfMass; }
142 }
143
144 public override OMV.Vector3 GeometricCenter
145 {
146 get { return Linkset.GeometricCenter; }
147 }
148
149 // Refresh the linkset structure and parameters when the prim's physical parameters are changed.
150 public override void UpdatePhysicalParameters()
151 {
152 base.UpdatePhysicalParameters();
153 // Recompute any linkset parameters.
154 // When going from non-physical to physical, this re-enables the constraints that
155 // had been automatically disabled when the mass was set to zero.
156 // For compound based linksets, this enables and disables interactions of the children.
157 if (Linkset != null) // null can happen during initialization
158 Linkset.Refresh(this);
159 }
160
161 // When the prim is made dynamic or static, the linkset needs to change.
162 protected override void MakeDynamic(bool makeStatic)
163 {
164 base.MakeDynamic(makeStatic);
165 if (Linkset != null) // null can happen during initialization
166 {
167 if (makeStatic)
168 Linkset.MakeStatic(this);
169 else
170 Linkset.MakeDynamic(this);
171 }
172 }
173
174 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
175 protected override void RemoveDependencies()
176 {
177 Linkset.RemoveDependencies(this);
178 base.RemoveDependencies();
179 }
180
181 // Called after a simulation step for the changes in physical object properties.
182 // Do any filtering/modification needed for linksets.
183 public override void UpdateProperties(EntityProperties entprop)
184 {
185 if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this))
186 {
187 // Properties are only updated for the roots of a linkset.
188 // TODO: this will have to change when linksets are articulated.
189 base.UpdateProperties(entprop);
190 }
191 /*
192 else
193 {
194 // For debugging, report the movement of children
195 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
196 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
197 entprop.Acceleration, entprop.RotationalVelocity);
198 }
199 */
200 // The linkset might like to know about changing locations
201 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
202 }
203
204 // Called after a simulation step to post a collision with this object.
205 // This returns 'true' if the collision has been queued and the SendCollisions call must
206 // be made at the end of the simulation step.
207 public override bool Collide(uint collidingWith, BSPhysObject collidee,
208 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
209 {
210 bool ret = false;
211 // Ask the linkset if it wants to handle the collision
212 if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth))
213 {
214 // The linkset didn't handle it so pass the collision through normal processing
215 ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
216 }
217 return ret;
218 }
219
220 // A linkset reports any collision on any part of the linkset.
221 public long SomeCollisionSimulationStep = 0;
222 public override bool HasSomeCollision
223 {
224 get
225 {
226 return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding;
227 }
228 set
229 {
230 if (value)
231 SomeCollisionSimulationStep = PhysScene.SimulationStep;
232 else
233 SomeCollisionSimulationStep = 0;
234
235 base.HasSomeCollision = value;
236 }
237 }
238
239 // Convert the existing linkset of this prim into a new type.
240 public bool ConvertLinkset(BSLinkset.LinksetImplementation newType)
241 {
242 bool ret = false;
243 if (LinksetType != newType)
244 {
245 DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType);
246
247 // Set the implementation type first so the call to BSLinkset.Factory gets the new type.
248 this.LinksetType = newType;
249
250 BSLinkset oldLinkset = this.Linkset;
251 BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this);
252
253 this.Linkset = newLinkset;
254
255 // Pick up any physical dependencies this linkset might have in the physics engine.
256 oldLinkset.RemoveDependencies(this);
257
258 // Create a list of the children (mainly because can't interate through a list that's changing)
259 List<BSPrimLinkable> children = new List<BSPrimLinkable>();
260 oldLinkset.ForEachMember((child) =>
261 {
262 if (!oldLinkset.IsRoot(child))
263 children.Add(child);
264 return false; // 'false' says to continue to next member
265 });
266
267 // Remove the children from the old linkset and add to the new (will be a new instance from the factory)
268 foreach (BSPrimLinkable child in children)
269 {
270 oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/);
271 }
272 foreach (BSPrimLinkable child in children)
273 {
274 newLinkset.AddMeToLinkset(child);
275 child.Linkset = newLinkset;
276 }
277
278 // Force the shape and linkset to get reconstructed
279 newLinkset.Refresh(this);
280 this.ForceBodyShapeRebuild(true /* inTaintTime */);
281 }
282 return ret;
283 }
284
285 #region Extension
286 public override object Extension(string pFunct, params object[] pParams)
287 {
288 DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length);
289 object ret = null;
290 switch (pFunct)
291 {
292 // physGetLinksetType();
293 // pParams = [ BSPhysObject root, null ]
294 case ExtendedPhysics.PhysFunctGetLinksetType:
295 {
296 ret = (object)LinksetType;
297 DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret);
298 break;
299 }
300 // physSetLinksetType(type);
301 // pParams = [ BSPhysObject root, null, integer type ]
302 case ExtendedPhysics.PhysFunctSetLinksetType:
303 {
304 if (pParams.Length > 2)
305 {
306 BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2];
307 if (Linkset.IsRoot(this))
308 {
309 PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate()
310 {
311 // Cause the linkset type to change
312 DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}",
313 LocalID, Linkset.LinksetImpl, linksetType);
314 ConvertLinkset(linksetType);
315 });
316 }
317 ret = (object)(int)linksetType;
318 }
319 break;
320 }
321 // physChangeLinkType(linknum, typeCode);
322 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
323 case ExtendedPhysics.PhysFunctChangeLinkType:
324 {
325 ret = Linkset.Extension(pFunct, pParams);
326 break;
327 }
328 // physGetLinkType(linknum);
329 // pParams = [ BSPhysObject root, BSPhysObject child ]
330 case ExtendedPhysics.PhysFunctGetLinkType:
331 {
332 ret = Linkset.Extension(pFunct, pParams);
333 break;
334 }
335 // physChangeLinkParams(linknum, [code, value, code, value, ...]);
336 // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ]
337 case ExtendedPhysics.PhysFunctChangeLinkParams:
338 {
339 ret = Linkset.Extension(pFunct, pParams);
340 break;
341 }
342 default:
343 ret = base.Extension(pFunct, pParams);
344 break;
345 }
346 return ret;
347 }
348 #endregion // Extension
349}
350}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
new file mode 100644
index 0000000..8a19944
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
@@ -0,0 +1,1281 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Linq;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using System.Threading;
34using OpenSim.Framework;
35using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework;
37using OpenSim.Region.CoreModules;
38using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
39using OpenSim.Region.Physics.Manager;
40using Nini.Config;
41using log4net;
42using OpenMetaverse;
43
44namespace OpenSim.Region.Physics.BulletSPlugin
45{
46public sealed class BSScene : PhysicsScene, IPhysicsParameters
47{
48 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
49 internal static readonly string LogHeader = "[BULLETS SCENE]";
50
51 // The name of the region we're working for.
52 public string RegionName { get; private set; }
53
54 public string BulletSimVersion = "?";
55
56 // The handle to the underlying managed or unmanaged version of Bullet being used.
57 public string BulletEngineName { get; private set; }
58 public BSAPITemplate PE;
59
60 // If the physics engine is running on a separate thread
61 public Thread m_physicsThread;
62
63 public Dictionary<uint, BSPhysObject> PhysObjects;
64 public BSShapeCollection Shapes;
65
66 // Keeping track of the objects with collisions so we can report begin and end of a collision
67 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
68 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
69
70 // All the collision processing is protected with this lock object
71 public Object CollisionLock = new Object();
72
73 // Properties are updated here
74 public Object UpdateLock = new Object();
75 public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>();
76
77 // Keep track of all the avatars so we can send them a collision event
78 // every tick so OpenSim will update its animation.
79 private HashSet<BSPhysObject> AvatarsInScene = new HashSet<BSPhysObject>();
80 private Object AvatarsInSceneLock = new Object();
81
82 // let my minuions use my logger
83 public ILog Logger { get { return m_log; } }
84
85 public IMesher mesher;
86 public uint WorldID { get; private set; }
87 public BulletWorld World { get; private set; }
88
89 // All the constraints that have been allocated in this instance.
90 public BSConstraintCollection Constraints { get; private set; }
91
92 // Simulation parameters
93 //internal float m_physicsStepTime; // if running independently, the interval simulated by default
94
95 internal int m_maxSubSteps;
96 internal float m_fixedTimeStep;
97
98 internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc.
99
100 internal long m_simulationStep = 0; // The current simulation step.
101 public long SimulationStep { get { return m_simulationStep; } }
102 // A number to use for SimulationStep that is probably not any step value
103 // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step.
104 public static long NotASimulationStep = -1234;
105
106 internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
107
108 internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
109
110 // Physical objects can register for prestep or poststep events
111 public delegate void PreStepAction(float timeStep);
112 public delegate void PostStepAction(float timeStep);
113 public event PreStepAction BeforeStep;
114 public event PostStepAction AfterStep;
115
116 // A value of the time 'now' so all the collision and update routines do not have to get their own
117 // Set to 'now' just before all the prims and actors are called for collisions and updates
118 public int SimulationNowTime { get; private set; }
119
120 // True if initialized and ready to do simulation steps
121 private bool m_initialized = false;
122
123 // Flag which is true when processing taints.
124 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
125 public bool InTaintTime { get; private set; }
126
127 // Pinned memory used to pass step information between managed and unmanaged
128 internal int m_maxCollisionsPerFrame;
129 internal CollisionDesc[] m_collisionArray;
130
131 internal int m_maxUpdatesPerFrame;
132 internal EntityProperties[] m_updateArray;
133
134 /// <summary>
135 /// Used to control physics simulation timing if Bullet is running on its own thread.
136 /// </summary>
137 private ManualResetEvent m_updateWaitEvent;
138
139 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
140 public const uint GROUNDPLANE_ID = 1;
141 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
142
143 public float SimpleWaterLevel { get; set; }
144 public BSTerrainManager TerrainManager { get; private set; }
145
146 public ConfigurationParameters Params
147 {
148 get { return UnmanagedParams[0]; }
149 }
150 public Vector3 DefaultGravity
151 {
152 get { return new Vector3(0f, 0f, Params.gravity); }
153 }
154 // Just the Z value of the gravity
155 public float DefaultGravityZ
156 {
157 get { return Params.gravity; }
158 }
159
160 // When functions in the unmanaged code must be called, it is only
161 // done at a known time just before the simulation step. The taint
162 // system saves all these function calls and executes them in
163 // order before the simulation.
164 public delegate void TaintCallback();
165 private struct TaintCallbackEntry
166 {
167 public String originator;
168 public String ident;
169 public TaintCallback callback;
170 public TaintCallbackEntry(string pIdent, TaintCallback pCallBack)
171 {
172 originator = BSScene.DetailLogZero;
173 ident = pIdent;
174 callback = pCallBack;
175 }
176 public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack)
177 {
178 originator = pOrigin;
179 ident = pIdent;
180 callback = pCallBack;
181 }
182 }
183 private Object _taintLock = new Object(); // lock for using the next object
184 private List<TaintCallbackEntry> _taintOperations;
185 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
186 private List<TaintCallbackEntry> _postStepOperations;
187
188 // A pointer to an instance if this structure is passed to the C++ code
189 // Used to pass basic configuration values to the unmanaged code.
190 internal ConfigurationParameters[] UnmanagedParams;
191
192 // Sometimes you just have to log everything.
193 public Logging.LogWriter PhysicsLogging;
194 private bool m_physicsLoggingEnabled;
195 private string m_physicsLoggingDir;
196 private string m_physicsLoggingPrefix;
197 private int m_physicsLoggingFileMinutes;
198 private bool m_physicsLoggingDoFlush;
199 private bool m_physicsPhysicalDumpEnabled;
200 public int PhysicsMetricDumpFrames { get; set; }
201 // 'true' of the vehicle code is to log lots of details
202 public bool VehicleLoggingEnabled { get; private set; }
203 public bool VehiclePhysicalLoggingEnabled { get; private set; }
204
205 #region Construction and Initialization
206 public BSScene(string engineType, string identifier)
207 {
208 m_initialized = false;
209
210 // The name of the region we're working for is passed to us. Keep for identification.
211 RegionName = identifier;
212
213 // Set identifying variables in the PhysicsScene interface.
214 EngineType = engineType;
215 Name = EngineType + "/" + RegionName;
216 }
217
218 // Old version of initialization that assumes legacy sized regions (256x256)
219 public override void Initialise(IMesher meshmerizer, IConfigSource config)
220 {
221 m_log.ErrorFormat("{0} WARNING WARNING WARNING! BulletSim initialized without region extent specification. Terrain will be messed up.");
222 Vector3 regionExtent = new Vector3( Constants.RegionSize, Constants.RegionSize, Constants.RegionSize);
223 Initialise(meshmerizer, config, regionExtent);
224
225 }
226
227 public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
228 {
229 mesher = meshmerizer;
230 _taintOperations = new List<TaintCallbackEntry>();
231 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
232 _postStepOperations = new List<TaintCallbackEntry>();
233 PhysObjects = new Dictionary<uint, BSPhysObject>();
234 Shapes = new BSShapeCollection(this);
235
236 m_simulatedTime = 0f;
237 LastTimeStep = 0.1f;
238
239 // Allocate pinned memory to pass parameters.
240 UnmanagedParams = new ConfigurationParameters[1];
241
242 // Set default values for physics parameters plus any overrides from the ini file
243 GetInitialParameterValues(config);
244
245 // Force some parameters to values depending on other configurations
246 // Only use heightmap terrain implementation if terrain larger than legacy size
247 if ((uint)regionExtent.X > Constants.RegionSize || (uint)regionExtent.Y > Constants.RegionSize)
248 {
249 m_log.WarnFormat("{0} Forcing terrain implementation to heightmap for large region", LogHeader);
250 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
251 }
252
253 // Get the connection to the physics engine (could be native or one of many DLLs)
254 PE = SelectUnderlyingBulletEngine(BulletEngineName);
255
256 // Enable very detailed logging.
257 // By creating an empty logger when not logging, the log message invocation code
258 // can be left in and every call doesn't have to check for null.
259 if (m_physicsLoggingEnabled)
260 {
261 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush);
262 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages.
263 }
264 else
265 {
266 PhysicsLogging = new Logging.LogWriter();
267 }
268
269 // Allocate memory for returning of the updates and collisions from the physics engine
270 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
271 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
272
273 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
274 // a child in a mega-region.
275 // Bullet actually doesn't care about the extents of the simulated
276 // area. It tracks active objects no matter where they are.
277 Vector3 worldExtent = regionExtent;
278
279 World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
280
281 Constraints = new BSConstraintCollection(World);
282
283 TerrainManager = new BSTerrainManager(this, worldExtent);
284 TerrainManager.CreateInitialGroundPlaneAndTerrain();
285
286 // Put some informational messages into the log file.
287 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
288
289 InTaintTime = false;
290 m_initialized = true;
291
292 // If the physics engine runs on its own thread, start same.
293 if (BSParam.UseSeparatePhysicsThread)
294 {
295 // The physics simulation should happen independently of the heartbeat loop
296 m_physicsThread
297 = WorkManager.StartThread(
298 BulletSPluginPhysicsThread,
299 string.Format("{0} ({1})", BulletEngineName, RegionName),
300 ThreadPriority.Normal,
301 true,
302 true);
303 }
304 }
305
306 // All default parameter values are set here. There should be no values set in the
307 // variable definitions.
308 private void GetInitialParameterValues(IConfigSource config)
309 {
310 ConfigurationParameters parms = new ConfigurationParameters();
311 UnmanagedParams[0] = parms;
312
313 BSParam.SetParameterDefaultValues(this);
314
315 if (config != null)
316 {
317 // If there are specifications in the ini file, use those values
318 IConfig pConfig = config.Configs["BulletSim"];
319 if (pConfig != null)
320 {
321 BSParam.SetParameterConfigurationValues(this, pConfig);
322
323 // There are two Bullet implementations to choose from
324 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
325
326 // Very detailed logging for physics debugging
327 // TODO: the boolean values can be moved to the normal parameter processing.
328 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
329 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
330 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
331 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
332 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
333 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
334 // Very detailed logging for vehicle debugging
335 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
336 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
337
338 // Do any replacements in the parameters
339 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
340 }
341 else
342 {
343 // Nothing in the configuration INI file so assume unmanaged and other defaults.
344 BulletEngineName = "BulletUnmanaged";
345 m_physicsLoggingEnabled = false;
346 VehicleLoggingEnabled = false;
347 }
348
349 // The material characteristics.
350 BSMaterials.InitializeFromDefaults(Params);
351 if (pConfig != null)
352 {
353 // Let the user add new and interesting material property values.
354 BSMaterials.InitializefromParameters(pConfig);
355 }
356 }
357 }
358
359 // A helper function that handles a true/false parameter and returns the proper float number encoding
360 float ParamBoolean(IConfig config, string parmName, float deflt)
361 {
362 float ret = deflt;
363 if (config.Contains(parmName))
364 {
365 ret = ConfigurationParameters.numericFalse;
366 if (config.GetBoolean(parmName, false))
367 {
368 ret = ConfigurationParameters.numericTrue;
369 }
370 }
371 return ret;
372 }
373
374 // Select the connection to the actual Bullet implementation.
375 // The main engine selection is the engineName up to the first hypen.
376 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
377 // is passed to the engine to do its special selection, etc.
378 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
379 {
380 // For the moment, do a simple switch statement.
381 // Someday do fancyness with looking up the interfaces in the assembly.
382 BSAPITemplate ret = null;
383
384 string selectionName = engineName.ToLower();
385 int hyphenIndex = engineName.IndexOf("-");
386 if (hyphenIndex > 0)
387 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
388
389 switch (selectionName)
390 {
391 case "bullet":
392 case "bulletunmanaged":
393 ret = new BSAPIUnman(engineName, this);
394 break;
395 case "bulletxna":
396 ret = new BSAPIXNA(engineName, this);
397 // Disable some features that are not implemented in BulletXNA
398 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
399 m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
400 BSParam.ShouldUseBulletHACD = false;
401 m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
402 BSParam.ShouldUseSingleConvexHullForPrims = false;
403 m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
404 BSParam.ShouldUseGImpactShapeForPrims = false;
405 m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
406 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
407 break;
408 }
409
410 if (ret == null)
411 {
412 m_log.ErrorFormat("{0} COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
413 }
414 else
415 {
416 m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
417 }
418
419 return ret;
420 }
421
422 public override void Dispose()
423 {
424 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
425
426 // make sure no stepping happens while we're deleting stuff
427 m_initialized = false;
428
429 lock (PhysObjects)
430 {
431 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
432 {
433 kvp.Value.Destroy();
434 }
435 PhysObjects.Clear();
436 }
437
438 // Now that the prims are all cleaned up, there should be no constraints left
439 if (Constraints != null)
440 {
441 Constraints.Dispose();
442 Constraints = null;
443 }
444
445 if (Shapes != null)
446 {
447 Shapes.Dispose();
448 Shapes = null;
449 }
450
451 if (TerrainManager != null)
452 {
453 TerrainManager.ReleaseGroundPlaneAndTerrain();
454 TerrainManager.Dispose();
455 TerrainManager = null;
456 }
457
458 // Anything left in the unmanaged code should be cleaned out
459 PE.Shutdown(World);
460
461 // Not logging any more
462 PhysicsLogging.Close();
463 }
464 #endregion // Construction and Initialization
465
466 #region Prim and Avatar addition and removal
467
468 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
469 {
470 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
471 return null;
472 }
473
474 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
475 {
476 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
477
478 if (!m_initialized) return null;
479
480 BSCharacter actor = new BSCharacter(localID, avName, this, position, velocity, size, isFlying);
481 lock (PhysObjects)
482 PhysObjects.Add(localID, actor);
483
484 // TODO: Remove kludge someday.
485 // We must generate a collision for avatars whether they collide or not.
486 // This is required by OpenSim to update avatar animations, etc.
487 lock (AvatarsInSceneLock)
488 AvatarsInScene.Add(actor);
489
490 return actor;
491 }
492
493 public override void RemoveAvatar(PhysicsActor actor)
494 {
495 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
496
497 if (!m_initialized) return;
498
499 BSCharacter bsactor = actor as BSCharacter;
500 if (bsactor != null)
501 {
502 try
503 {
504 lock (PhysObjects)
505 PhysObjects.Remove(bsactor.LocalID);
506 // Remove kludge someday
507 lock (AvatarsInSceneLock)
508 AvatarsInScene.Remove(bsactor);
509 }
510 catch (Exception e)
511 {
512 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
513 }
514 bsactor.Destroy();
515 // bsactor.dispose();
516 }
517 else
518 {
519 m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
520 LogHeader, actor.LocalID, actor.GetType().Name);
521 }
522 }
523
524 public override void RemovePrim(PhysicsActor prim)
525 {
526 if (!m_initialized) return;
527
528 BSPhysObject bsprim = prim as BSPhysObject;
529 if (bsprim != null)
530 {
531 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
532 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
533 try
534 {
535 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
536 }
537 catch (Exception e)
538 {
539 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
540 }
541 bsprim.Destroy();
542 // bsprim.dispose();
543 }
544 else
545 {
546 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
547 }
548 }
549
550 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
551 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
552 {
553 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
554
555 if (!m_initialized) return null;
556
557 // DetailLog("{0},BSScene.AddPrimShape,call", localID);
558
559 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
560 lock (PhysObjects) PhysObjects.Add(localID, prim);
561 return prim;
562 }
563
564 // This is a call from the simulator saying that some physical property has been updated.
565 // The BulletSim driver senses the changing of relevant properties so this taint
566 // information call is not needed.
567 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
568
569 #endregion // Prim and Avatar addition and removal
570
571 #region Simulation
572
573 // Call from the simulator to send physics information to the simulator objects.
574 // This pushes all the collision and property update events into the objects in
575 // the simulator and, since it is on the heartbeat thread, there is an implicit
576 // locking of those data structures from other heartbeat events.
577 // If the physics engine is running on a separate thread, the update information
578 // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
579 public override float Simulate(float timeStep)
580 {
581 if (!BSParam.UseSeparatePhysicsThread)
582 {
583 DoPhysicsStep(timeStep);
584 }
585 return SendUpdatesToSimulator(timeStep);
586 }
587
588 // Call the physics engine to do one 'timeStep' and collect collisions and updates
589 // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
590 private void DoPhysicsStep(float timeStep)
591 {
592 // prevent simulation until we've been initialized
593 if (!m_initialized) return;
594
595 LastTimeStep = timeStep;
596
597 int updatedEntityCount = 0;
598 int collidersCount = 0;
599
600 int beforeTime = Util.EnvironmentTickCount();
601 int simTime = 0;
602
603 int numTaints = _taintOperations.Count;
604 InTaintTime = true; // Only used for debugging so locking is not necessary.
605
606 // update the prim states while we know the physics engine is not busy
607 ProcessTaints();
608
609 // Some of the physical objects requre individual, pre-step calls
610 // (vehicles and avatar movement, in particular)
611 TriggerPreStepEvent(timeStep);
612
613 // the prestep actions might have added taints
614 numTaints += _taintOperations.Count;
615 ProcessTaints();
616
617 InTaintTime = false; // Only used for debugging so locking is not necessary.
618
619 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
620 // Only enable this in a limited test world with few objects.
621 if (m_physicsPhysicalDumpEnabled)
622 PE.DumpAllInfo(World);
623
624 // step the physical world one interval
625 m_simulationStep++;
626 int numSubSteps = 0;
627 try
628 {
629 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
630
631 }
632 catch (Exception e)
633 {
634 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
635 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
636 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
637 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
638 updatedEntityCount = 0;
639 collidersCount = 0;
640 }
641
642 // Make the physics engine dump useful statistics periodically
643 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
644 PE.DumpPhysicsStatistics(World);
645
646 // Get a value for 'now' so all the collision and update routines don't have to get their own.
647 SimulationNowTime = Util.EnvironmentTickCount();
648
649 // Send collision information to the colliding objects. The objects decide if the collision
650 // is 'real' (like linksets don't collide with themselves) and the individual objects
651 // know if the simulator has subscribed to collisions.
652 lock (CollisionLock)
653 {
654 if (collidersCount > 0)
655 {
656 lock (PhysObjects)
657 {
658 for (int ii = 0; ii < collidersCount; ii++)
659 {
660 uint cA = m_collisionArray[ii].aID;
661 uint cB = m_collisionArray[ii].bID;
662 Vector3 point = m_collisionArray[ii].point;
663 Vector3 normal = m_collisionArray[ii].normal;
664 float penetration = m_collisionArray[ii].penetration;
665 SendCollision(cA, cB, point, normal, penetration);
666 SendCollision(cB, cA, point, -normal, penetration);
667 }
668 }
669 }
670 }
671
672 // If any of the objects had updated properties, tell the managed objects about the update
673 // and remember that there was a change so it will be passed to the simulator.
674 lock (UpdateLock)
675 {
676 if (updatedEntityCount > 0)
677 {
678 lock (PhysObjects)
679 {
680 for (int ii = 0; ii < updatedEntityCount; ii++)
681 {
682 EntityProperties entprop = m_updateArray[ii];
683 BSPhysObject pobj;
684 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
685 {
686 if (pobj.IsInitialized)
687 pobj.UpdateProperties(entprop);
688 }
689 }
690 }
691 }
692 }
693
694 // Some actors want to know when the simulation step is complete.
695 TriggerPostStepEvent(timeStep);
696
697 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
698 if (PhysicsLogging.Enabled)
699 {
700 DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
701 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
702 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
703 }
704
705 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
706 // Only enable this in a limited test world with few objects.
707 if (m_physicsPhysicalDumpEnabled)
708 PE.DumpAllInfo(World);
709
710 // The physics engine returns the number of milliseconds it simulated this call.
711 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
712 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
713 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
714 }
715
716 // Called by a BSPhysObject to note that it has changed properties and this information
717 // should be passed up to the simulator at the proper time.
718 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
719 // this is is under UpdateLock.
720 public void PostUpdate(BSPhysObject updatee)
721 {
722 lock (UpdateLock)
723 {
724 ObjectsWithUpdates.Add(updatee);
725 }
726 }
727
728 // The simulator thinks it is physics time so return all the collisions and position
729 // updates that were collected in actual physics simulation.
730 private float SendUpdatesToSimulator(float timeStep)
731 {
732 if (!m_initialized) return 5.0f;
733
734 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
735 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
736 // Push the collisions into the simulator.
737 lock (CollisionLock)
738 {
739 if (ObjectsWithCollisions.Count > 0)
740 {
741 foreach (BSPhysObject bsp in ObjectsWithCollisions)
742 if (!bsp.SendCollisions())
743 {
744 // If the object is done colliding, see that it's removed from the colliding list
745 ObjectsWithNoMoreCollisions.Add(bsp);
746 }
747 }
748
749 // This is a kludge to get avatar movement updates.
750 // The simulator expects collisions for avatars even if there are have been no collisions.
751 // The event updates avatar animations and stuff.
752 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
753 // Note that we get a copy of the list to search because SendCollision() can take a while.
754 HashSet<BSPhysObject> tempAvatarsInScene;
755 lock (AvatarsInSceneLock)
756 {
757 tempAvatarsInScene = new HashSet<BSPhysObject>(AvatarsInScene);
758 }
759 foreach (BSPhysObject actor in tempAvatarsInScene)
760 {
761 if (!ObjectsWithCollisions.Contains(actor)) // don't call avatars twice
762 actor.SendCollisions();
763 }
764 tempAvatarsInScene = null;
765
766 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
767 // Not done above because it is inside an iteration of ObjectWithCollisions.
768 // This complex collision processing is required to create an empty collision
769 // event call after all real collisions have happened on an object. This allows
770 // the simulator to generate the 'collision end' event.
771 if (ObjectsWithNoMoreCollisions.Count > 0)
772 {
773 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
774 ObjectsWithCollisions.Remove(po);
775 ObjectsWithNoMoreCollisions.Clear();
776 }
777 }
778
779 // Call the simulator for each object that has physics property updates.
780 HashSet<BSPhysObject> updatedObjects = null;
781 lock (UpdateLock)
782 {
783 if (ObjectsWithUpdates.Count > 0)
784 {
785 updatedObjects = ObjectsWithUpdates;
786 ObjectsWithUpdates = new HashSet<BSPhysObject>();
787 }
788 }
789 if (updatedObjects != null)
790 {
791 foreach (BSPhysObject obj in updatedObjects)
792 {
793 obj.RequestPhysicsterseUpdate();
794 }
795 updatedObjects.Clear();
796 }
797
798 // Return the framerate simulated to give the above returned results.
799 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
800 float simTime = m_simulatedTime;
801 m_simulatedTime = 0f;
802 return simTime;
803 }
804
805 // Something has collided
806 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
807 {
808 if (localID <= TerrainManager.HighestTerrainID)
809 {
810 return; // don't send collisions to the terrain
811 }
812
813 BSPhysObject collider;
814 // NOTE that PhysObjects was locked before the call to SendCollision().
815 if (!PhysObjects.TryGetValue(localID, out collider))
816 {
817 // If the object that is colliding cannot be found, just ignore the collision.
818 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
819 return;
820 }
821
822 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
823 BSPhysObject collidee = null;
824 PhysObjects.TryGetValue(collidingWith, out collidee);
825
826 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
827
828 if (collider.IsInitialized)
829 {
830 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
831 {
832 // If a collision was 'good', remember to send it to the simulator
833 lock (CollisionLock)
834 {
835 ObjectsWithCollisions.Add(collider);
836 }
837 }
838 }
839
840 return;
841 }
842
843 public void BulletSPluginPhysicsThread()
844 {
845 Thread.CurrentThread.Priority = ThreadPriority.Highest;
846 m_updateWaitEvent = new ManualResetEvent(false);
847
848 while (m_initialized)
849 {
850 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
851
852 if (BSParam.Active)
853 DoPhysicsStep(BSParam.PhysicsTimeStep);
854
855 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
856 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
857
858 if (simulationTimeVsRealtimeDifferenceMS > 0)
859 {
860 // The simulation of the time interval took less than realtime.
861 // Do a wait for the rest of realtime.
862 m_updateWaitEvent.WaitOne(simulationTimeVsRealtimeDifferenceMS);
863 //Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
864 }
865 else
866 {
867 // The simulation took longer than realtime.
868 // Do some scaling of simulation time.
869 // TODO.
870 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
871 }
872
873 Watchdog.UpdateThread();
874 }
875
876 Watchdog.RemoveThread();
877 }
878
879 #endregion // Simulation
880
881 public override void GetResults() { }
882
883 #region Terrain
884
885 public override void SetTerrain(float[] heightMap) {
886 TerrainManager.SetTerrain(heightMap);
887 }
888
889 public override void SetWaterLevel(float baseheight)
890 {
891 SimpleWaterLevel = baseheight;
892 }
893
894 public override void DeleteTerrain()
895 {
896 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
897 }
898
899 // Although no one seems to check this, I do support combining.
900 public override bool SupportsCombining()
901 {
902 return TerrainManager.SupportsCombining();
903 }
904 // This call says I am a child to region zero in a mega-region. 'pScene' is that
905 // of region zero, 'offset' is my offset from regions zero's origin, and
906 // 'extents' is the largest XY that is handled in my region.
907 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
908 {
909 TerrainManager.Combine(pScene, offset, extents);
910 }
911
912 // Unhook all the combining that I know about.
913 public override void UnCombine(PhysicsScene pScene)
914 {
915 TerrainManager.UnCombine(pScene);
916 }
917
918 #endregion // Terrain
919
920 public override Dictionary<uint, float> GetTopColliders()
921 {
922 Dictionary<uint, float> topColliders;
923
924 lock (PhysObjects)
925 {
926 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
927 {
928 kvp.Value.ComputeCollisionScore();
929 }
930
931 List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values);
932 orderedPrims.OrderByDescending(p => p.CollisionScore);
933 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
934 }
935
936 return topColliders;
937 }
938
939 public override bool IsThreaded { get { return false; } }
940
941 #region Extensions
942 public override object Extension(string pFunct, params object[] pParams)
943 {
944 DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct);
945 return base.Extension(pFunct, pParams);
946 }
947 #endregion // Extensions
948
949 public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs)
950 {
951 float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f;
952 float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f;
953 float pathBegin = (float)pbs.PathBegin * 2.0e-5f;
954 float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f;
955 float pathScaleX = (float)(200 - pbs.PathScaleX) * 0.01f;
956 float pathScaleY = (float)(200 - pbs.PathScaleY) * 0.01f;
957 float pathTaperX = pbs.PathTaperX * 0.01f;
958 float pathTaperY = pbs.PathTaperY * 0.01f;
959
960 float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f;
961 float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f;
962 float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f;
963 if (profileHollow > 0.95f)
964 profileHollow = 0.95f;
965
966 StringBuilder buff = new StringBuilder();
967 buff.Append("shape=");
968 buff.Append(((ProfileShape)pbs.ProfileShape).ToString());
969 buff.Append(",");
970 buff.Append("hollow=");
971 buff.Append(((HollowShape)pbs.HollowShape).ToString());
972 buff.Append(",");
973 buff.Append("pathCurve=");
974 buff.Append(((Extrusion)pbs.PathCurve).ToString());
975 buff.Append(",");
976 buff.Append("profCurve=");
977 buff.Append(((Extrusion)pbs.ProfileCurve).ToString());
978 buff.Append(",");
979 buff.Append("profHollow=");
980 buff.Append(profileHollow.ToString());
981 buff.Append(",");
982 buff.Append("pathBegEnd=");
983 buff.Append(pathBegin.ToString());
984 buff.Append("/");
985 buff.Append(pathEnd.ToString());
986 buff.Append(",");
987 buff.Append("profileBegEnd=");
988 buff.Append(profileBegin.ToString());
989 buff.Append("/");
990 buff.Append(profileEnd.ToString());
991 buff.Append(",");
992 buff.Append("scaleXY=");
993 buff.Append(pathScaleX.ToString());
994 buff.Append("/");
995 buff.Append(pathScaleY.ToString());
996 buff.Append(",");
997 buff.Append("shearXY=");
998 buff.Append(pathShearX.ToString());
999 buff.Append("/");
1000 buff.Append(pathShearY.ToString());
1001 buff.Append(",");
1002 buff.Append("taperXY=");
1003 buff.Append(pbs.PathTaperX.ToString());
1004 buff.Append("/");
1005 buff.Append(pbs.PathTaperY.ToString());
1006 buff.Append(",");
1007 buff.Append("skew=");
1008 buff.Append(pbs.PathSkew.ToString());
1009 buff.Append(",");
1010 buff.Append("twist/Beg=");
1011 buff.Append(pbs.PathTwist.ToString());
1012 buff.Append("/");
1013 buff.Append(pbs.PathTwistBegin.ToString());
1014
1015 return buff.ToString();
1016 }
1017
1018 #region Taints
1019 // The simulation execution order is:
1020 // Simulate()
1021 // DoOneTimeTaints
1022 // TriggerPreStepEvent
1023 // DoOneTimeTaints
1024 // Step()
1025 // ProcessAndSendToSimulatorCollisions
1026 // ProcessAndSendToSimulatorPropertyUpdates
1027 // TriggerPostStepEvent
1028
1029 // Calls to the PhysicsActors can't directly call into the physics engine
1030 // because it might be busy. We delay changes to a known time.
1031 // We rely on C#'s closure to save and restore the context for the delegate.
1032 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
1033 {
1034 TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback);
1035 }
1036 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
1037 {
1038 TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1039 }
1040 public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1041 {
1042 TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
1043 }
1044 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1045 {
1046 TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1047 }
1048 // Sometimes a potentially tainted operation can be used in and out of taint time.
1049 // This routine executes the command immediately if in taint-time otherwise it is queued.
1050 public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback)
1051 {
1052 if (!m_initialized) return;
1053
1054 if (inTaintTime)
1055 pCallback();
1056 else
1057 {
1058 lock (_taintLock)
1059 {
1060 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
1061 }
1062 }
1063 }
1064
1065 private void TriggerPreStepEvent(float timeStep)
1066 {
1067 PreStepAction actions = BeforeStep;
1068 if (actions != null)
1069 actions(timeStep);
1070
1071 }
1072
1073 private void TriggerPostStepEvent(float timeStep)
1074 {
1075 PostStepAction actions = AfterStep;
1076 if (actions != null)
1077 actions(timeStep);
1078
1079 }
1080
1081 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
1082 // a callback into itself to do the actual property change. That callback is called
1083 // here just before the physics engine is called to step the simulation.
1084 public void ProcessTaints()
1085 {
1086 ProcessRegularTaints();
1087 ProcessPostTaintTaints();
1088 }
1089
1090 private void ProcessRegularTaints()
1091 {
1092 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
1093 {
1094 // swizzle a new list into the list location so we can process what's there
1095 List<TaintCallbackEntry> oldList;
1096 lock (_taintLock)
1097 {
1098 oldList = _taintOperations;
1099 _taintOperations = new List<TaintCallbackEntry>();
1100 }
1101
1102 foreach (TaintCallbackEntry tcbe in oldList)
1103 {
1104 try
1105 {
1106 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
1107 tcbe.callback();
1108 }
1109 catch (Exception e)
1110 {
1111 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
1112 }
1113 }
1114 oldList.Clear();
1115 }
1116 }
1117
1118 // Schedule an update to happen after all the regular taints are processed.
1119 // Note that new requests for the same operation ("ident") for the same object ("ID")
1120 // will replace any previous operation by the same object.
1121 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
1122 {
1123 string IDAsString = ID.ToString();
1124 string uniqueIdent = ident + "-" + IDAsString;
1125 lock (_taintLock)
1126 {
1127 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback);
1128 }
1129
1130 return;
1131 }
1132
1133 // Taints that happen after the normal taint processing but before the simulation step.
1134 private void ProcessPostTaintTaints()
1135 {
1136 if (m_initialized && _postTaintOperations.Count > 0)
1137 {
1138 Dictionary<string, TaintCallbackEntry> oldList;
1139 lock (_taintLock)
1140 {
1141 oldList = _postTaintOperations;
1142 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
1143 }
1144
1145 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
1146 {
1147 try
1148 {
1149 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
1150 kvp.Value.callback();
1151 }
1152 catch (Exception e)
1153 {
1154 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
1155 }
1156 }
1157 oldList.Clear();
1158 }
1159 }
1160
1161 // Only used for debugging. Does not change state of anything so locking is not necessary.
1162 public bool AssertInTaintTime(string whereFrom)
1163 {
1164 if (!InTaintTime)
1165 {
1166 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
1167 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
1168 // Util.PrintCallStack(DetailLog);
1169 }
1170 return InTaintTime;
1171 }
1172
1173 #endregion // Taints
1174
1175 #region IPhysicsParameters
1176 // Get the list of parameters this physics engine supports
1177 public PhysParameterEntry[] GetParameterList()
1178 {
1179 BSParam.BuildParameterTable();
1180 return BSParam.SettableParameters;
1181 }
1182
1183 // Set parameter on a specific or all instances.
1184 // Return 'false' if not able to set the parameter.
1185 // Setting the value in the m_params block will change the value the physics engine
1186 // will use the next time since it's pinned and shared memory.
1187 // Some of the values require calling into the physics engine to get the new
1188 // value activated ('terrainFriction' for instance).
1189 public bool SetPhysicsParameter(string parm, string val, uint localID)
1190 {
1191 bool ret = false;
1192
1193 BSParam.ParameterDefnBase theParam;
1194 if (BSParam.TryGetParameter(parm, out theParam))
1195 {
1196 // Set the value in the C# code
1197 theParam.SetValue(this, val);
1198
1199 // Optionally set the parameter in the unmanaged code
1200 if (theParam.HasSetOnObject)
1201 {
1202 // update all the localIDs specified
1203 // If the local ID is APPLY_TO_NONE, just change the default value
1204 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1205 // If the localID is a specific object, apply the parameter change to only that object
1206 List<uint> objectIDs = new List<uint>();
1207 switch (localID)
1208 {
1209 case PhysParameterEntry.APPLY_TO_NONE:
1210 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1211 objectIDs.Add(TERRAIN_ID);
1212 TaintedUpdateParameter(parm, objectIDs, val);
1213 break;
1214 case PhysParameterEntry.APPLY_TO_ALL:
1215 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1216 TaintedUpdateParameter(parm, objectIDs, val);
1217 break;
1218 default:
1219 // setting only one localID
1220 objectIDs.Add(localID);
1221 TaintedUpdateParameter(parm, objectIDs, val);
1222 break;
1223 }
1224 }
1225
1226 ret = true;
1227 }
1228 return ret;
1229 }
1230
1231 // schedule the actual updating of the paramter to when the phys engine is not busy
1232 private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val)
1233 {
1234 string xval = val;
1235 List<uint> xlIDs = lIDs;
1236 string xparm = parm;
1237 TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() {
1238 BSParam.ParameterDefnBase thisParam;
1239 if (BSParam.TryGetParameter(xparm, out thisParam))
1240 {
1241 if (thisParam.HasSetOnObject)
1242 {
1243 foreach (uint lID in xlIDs)
1244 {
1245 BSPhysObject theObject = null;
1246 if (PhysObjects.TryGetValue(lID, out theObject))
1247 thisParam.SetOnObject(this, theObject);
1248 }
1249 }
1250 }
1251 });
1252 }
1253
1254 // Get parameter.
1255 // Return 'false' if not able to get the parameter.
1256 public bool GetPhysicsParameter(string parm, out string value)
1257 {
1258 string val = String.Empty;
1259 bool ret = false;
1260 BSParam.ParameterDefnBase theParam;
1261 if (BSParam.TryGetParameter(parm, out theParam))
1262 {
1263 val = theParam.GetValue(this);
1264 ret = true;
1265 }
1266 value = val;
1267 return ret;
1268 }
1269
1270 #endregion IPhysicsParameters
1271
1272 // Invoke the detailed logger and output something if it's enabled.
1273 public void DetailLog(string msg, params Object[] args)
1274 {
1275 PhysicsLogging.Write(msg, args);
1276 }
1277 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1278 public const string DetailLogZero = "0000000000";
1279
1280}
1281}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
new file mode 100755
index 0000000..d1de844
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
@@ -0,0 +1,425 @@
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;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public sealed class BSShapeCollection : IDisposable
38{
39#pragma warning disable 414
40 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
41#pragma warning restore 414
42
43 private BSScene m_physicsScene { get; set; }
44
45 private Object m_collectionActivityLock = new Object();
46
47 private bool DDetail = false;
48
49 public BSShapeCollection(BSScene physScene)
50 {
51 m_physicsScene = physScene;
52 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
53 // While detailed debugging is still active, this is better than commenting out all the
54 // DetailLog statements. When debugging slows down, this and the protected logging
55 // statements can be commented/removed.
56 DDetail = true;
57 }
58
59 public void Dispose()
60 {
61 // TODO!!!!!!!!!
62 }
63
64 // Callbacks called just before either the body or shape is destroyed.
65 // Mostly used for changing bodies out from under Linksets.
66 // Useful for other cases where parameters need saving.
67 // Passing 'null' says no callback.
68 public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
69
70 // Called to update/change the body and shape for an object.
71 // The object has some shape and body on it. Here we decide if that is the correct shape
72 // for the current state of the object (static/dynamic/...).
73 // If bodyCallback is not null, it is called if either the body or the shape are changed
74 // so dependencies (like constraints) can be removed before the physical object is dereferenced.
75 // Return 'true' if either the body or the shape changed.
76 // Called at taint-time.
77 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
78 {
79 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
80
81 bool ret = false;
82
83 // This lock could probably be pushed down lower but building shouldn't take long
84 lock (m_collectionActivityLock)
85 {
86 // Do we have the correct geometry for this type of object?
87 // Updates prim.BSShape with information/pointers to shape.
88 // Returns 'true' of BSShape is changed to a new shape.
89 bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
90 // If we had to select a new shape geometry for the object,
91 // rebuild the body around it.
92 // Updates prim.BSBody with information/pointers to requested body
93 // Returns 'true' if BSBody was changed.
94 bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
95 ret = newGeom || newBody;
96 }
97 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
98 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
99
100 return ret;
101 }
102
103 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
104 {
105 return GetBodyAndShape(forceRebuild, sim, prim, null);
106 }
107
108 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
109 // before replacing it.
110 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
111 {
112 if (prim.PhysShape.HasPhysicalShape)
113 {
114 if (shapeCallback != null)
115 shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
116 prim.PhysShape.Dereference(m_physicsScene);
117 }
118 prim.PhysShape = new BSShapeNull();
119 }
120
121 // Create the geometry information in Bullet for later use.
122 // The objects needs a hull if it's physical otherwise a mesh is enough.
123 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
124 // shared geometries will be used. If the parameters of the existing shape are the same
125 // as this request, the shape is not rebuilt.
126 // Info in prim.BSShape is updated to the new shape.
127 // Returns 'true' if the geometry was rebuilt.
128 // Called at taint-time!
129 public const int AvatarShapeCapsule = 0;
130 public const int AvatarShapeCube = 1;
131 public const int AvatarShapeOvoid = 2;
132 public const int AvatarShapeMesh = 3;
133 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
134 {
135 bool ret = false;
136 bool haveShape = false;
137 bool nativeShapePossible = true;
138 PrimitiveBaseShape pbs = prim.BaseShape;
139
140 // Kludge to create the capsule for the avatar.
141 // TDOD: Remove/redo this when BSShapeAvatar is working!!
142 BSCharacter theChar = prim as BSCharacter;
143 if (theChar != null)
144 {
145 DereferenceExistingShape(prim, shapeCallback);
146 switch (BSParam.AvatarShape)
147 {
148 case AvatarShapeCapsule:
149 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
150 BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
151 ret = true;
152 haveShape = true;
153 break;
154 case AvatarShapeCube:
155 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
156 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE);
157 ret = true;
158 haveShape = true;
159 break;
160 case AvatarShapeOvoid:
161 // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape
162 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
163 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE);
164 ret = true;
165 haveShape = true;
166 break;
167 case AvatarShapeMesh:
168 break;
169 default:
170 break;
171 }
172 }
173
174 // If the prim attributes are simple, this could be a simple Bullet native shape
175 // Native shapes work whether to object is static or physical.
176 if (!haveShape
177 && nativeShapePossible
178 && pbs != null
179 && PrimHasNoCuts(pbs)
180 && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
181 )
182 {
183 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
184 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
185 if (prim.PhysShape.HasPhysicalShape)
186 scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
187
188 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
189 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
190
191 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
192 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
193 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
194 {
195 haveShape = true;
196 if (forceRebuild
197 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
198 )
199 {
200 DereferenceExistingShape(prim, shapeCallback);
201 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
202 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
203 ret = true;
204 }
205 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
206 prim.LocalID, forceRebuild, ret, prim.PhysShape);
207 }
208 // If we didn't make a sphere, maybe a box will work.
209 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
210 {
211 haveShape = true;
212 if (forceRebuild
213 || prim.Scale != scaleOfExistingShape
214 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
215 )
216 {
217 DereferenceExistingShape(prim, shapeCallback);
218 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
219 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
220 ret = true;
221 }
222 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
223 prim.LocalID, forceRebuild, ret, prim.PhysShape);
224 }
225 }
226
227 // If a simple shape is not happening, create a mesh and possibly a hull.
228 if (!haveShape && pbs != null)
229 {
230 ret = CreateGeomMeshOrHull(prim, shapeCallback);
231 }
232
233 return ret;
234 }
235
236 // return 'true' if this shape description does not include any cutting or twisting.
237 public static bool PrimHasNoCuts(PrimitiveBaseShape pbs)
238 {
239 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
240 && pbs.ProfileHollow == 0
241 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
242 && pbs.PathBegin == 0 && pbs.PathEnd == 0
243 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
244 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
245 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
246 }
247
248 // return 'true' if the prim's shape was changed.
249 private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
250 {
251
252 bool ret = false;
253 // Note that if it's a native shape, the check for physical/non-physical is not
254 // made. Native shapes work in either case.
255 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
256 {
257 // Use a simple, single mesh convex hull shape if the object is simple enough
258 BSShape potentialHull = null;
259
260 PrimitiveBaseShape pbs = prim.BaseShape;
261 // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists)
262 if (BSParam.ShouldUseSingleConvexHullForPrims
263 && pbs != null
264 && !pbs.SculptEntry
265 && PrimHasNoCuts(pbs)
266 )
267 {
268 potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
269 }
270 // Use the GImpact shape if it is a prim that has some concaveness
271 if (potentialHull == null
272 && BSParam.ShouldUseGImpactShapeForPrims
273 && pbs != null
274 && !pbs.SculptEntry
275 )
276 {
277 potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim);
278 }
279 // If not any of the simple cases, just make a hull
280 if (potentialHull == null)
281 {
282 potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
283 }
284
285 // If the current shape is not what is on the prim at the moment, time to change.
286 if (!prim.PhysShape.HasPhysicalShape
287 || potentialHull.ShapeType != prim.PhysShape.ShapeType
288 || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
289 {
290 DereferenceExistingShape(prim, shapeCallback);
291 prim.PhysShape = potentialHull;
292 ret = true;
293 }
294 else
295 {
296 // The current shape on the prim is the correct one. We don't need the potential reference.
297 potentialHull.Dereference(m_physicsScene);
298 }
299 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
300 }
301 else
302 {
303 // Non-physical objects should be just meshes.
304 BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
305 // If the current shape is not what is on the prim at the moment, time to change.
306 if (!prim.PhysShape.HasPhysicalShape
307 || potentialMesh.ShapeType != prim.PhysShape.ShapeType
308 || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
309 {
310 DereferenceExistingShape(prim, shapeCallback);
311 prim.PhysShape = potentialMesh;
312 ret = true;
313 }
314 else
315 {
316 // We don't need this reference to the mesh that is already being using.
317 potentialMesh.Dereference(m_physicsScene);
318 }
319 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
320 }
321 return ret;
322 }
323
324 // Track another user of a body.
325 // We presume the caller has allocated the body.
326 // Bodies only have one user so the body is just put into the world if not already there.
327 private void ReferenceBody(BulletBody body)
328 {
329 lock (m_collectionActivityLock)
330 {
331 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
332 if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
333 {
334 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
335 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
336 }
337 }
338 }
339
340 // Release the usage of a body.
341 // Called when releasing use of a BSBody. BSShape is handled separately.
342 // Called in taint time.
343 public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
344 {
345 if (!body.HasPhysicalBody)
346 return;
347
348 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
349
350 lock (m_collectionActivityLock)
351 {
352 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
353 // If the caller needs to know the old body is going away, pass the event up.
354 if (bodyCallback != null)
355 bodyCallback(body, null);
356
357 // Removing an object not in the world is a NOOP
358 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
359
360 // Zero any reference to the shape so it is not freed when the body is deleted.
361 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
362
363 m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
364 }
365 }
366
367 // Create a body object in Bullet.
368 // Updates prim.BSBody with the information about the new body if one is created.
369 // Returns 'true' if an object was actually created.
370 // Called at taint-time.
371 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
372 {
373 bool ret = false;
374
375 // the mesh, hull or native shape must have already been created in Bullet
376 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
377
378 // If there is an existing body, verify it's of an acceptable type.
379 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
380 if (!mustRebuild)
381 {
382 CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
383 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
384 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
385 {
386 // If the collisionObject is not the correct type for solidness, rebuild what's there
387 mustRebuild = true;
388 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
389 }
390 }
391
392 if (mustRebuild || forceRebuild)
393 {
394 // Free any old body
395 DereferenceBody(prim.PhysBody, bodyCallback);
396
397 BulletBody aBody;
398 if (prim.IsSolid)
399 {
400 aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
401 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
402 }
403 else
404 {
405 aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
406 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
407 }
408
409 ReferenceBody(aBody);
410
411 prim.PhysBody = aBody;
412
413 ret = true;
414 }
415
416 return ret;
417 }
418
419 private void DetailLog(string msg, params Object[] args)
420 {
421 if (m_physicsScene.PhysicsLogging.Enabled)
422 m_physicsScene.DetailLog(msg, args);
423 }
424}
425}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
new file mode 100755
index 0000000..86d86cb
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
@@ -0,0 +1,1463 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Text;
31
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.Meshing;
35using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36
37using OMV = OpenMetaverse;
38
39namespace OpenSim.Region.Physics.BulletSPlugin
40{
41// Information class that holds stats for the shape. Which values mean
42// something depends on the type of shape.
43// This information is used for debugging and stats and is not used
44// for operational things.
45public class ShapeInfoInfo
46{
47 public int Vertices { get; set; }
48 private int m_hullCount;
49 private int[] m_verticesPerHull;
50 public ShapeInfoInfo()
51 {
52 Vertices = 0;
53 m_hullCount = 0;
54 m_verticesPerHull = null;
55 }
56 public int HullCount
57 {
58 set
59 {
60 m_hullCount = value;
61 m_verticesPerHull = new int[m_hullCount];
62 Array.Clear(m_verticesPerHull, 0, m_hullCount);
63 }
64 get { return m_hullCount; }
65 }
66 public void SetVerticesPerHull(int hullNum, int vertices)
67 {
68 if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
69 {
70 m_verticesPerHull[hullNum] = vertices;
71 }
72 }
73 public int GetVerticesPerHull(int hullNum)
74 {
75 if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
76 {
77 return m_verticesPerHull[hullNum];
78 }
79 return 0;
80 }
81 public override string ToString()
82 {
83 StringBuilder buff = new StringBuilder();
84 // buff.Append("ShapeInfo=<");
85 buff.Append("<");
86 if (Vertices > 0)
87 {
88 buff.Append("verts=");
89 buff.Append(Vertices.ToString());
90 }
91
92 if (Vertices > 0 && HullCount > 0) buff.Append(",");
93
94 if (HullCount > 0)
95 {
96 buff.Append("nHulls=");
97 buff.Append(HullCount.ToString());
98 buff.Append(",");
99 buff.Append("hullVerts=");
100 for (int ii = 0; ii < HullCount; ii++)
101 {
102 if (ii != 0) buff.Append(",");
103 buff.Append(GetVerticesPerHull(ii).ToString());
104 }
105 }
106 buff.Append(">");
107 return buff.ToString();
108 }
109}
110
111public abstract class BSShape
112{
113 private static string LogHeader = "[BULLETSIM SHAPE]";
114
115 public int referenceCount { get; set; }
116 public DateTime lastReferenced { get; set; }
117 public BulletShape physShapeInfo { get; set; }
118 public ShapeInfoInfo shapeInfo { get; private set; }
119
120 public BSShape()
121 {
122 referenceCount = 1;
123 lastReferenced = DateTime.Now;
124 physShapeInfo = new BulletShape();
125 shapeInfo = new ShapeInfoInfo();
126 }
127 public BSShape(BulletShape pShape)
128 {
129 referenceCount = 1;
130 lastReferenced = DateTime.Now;
131 physShapeInfo = pShape;
132 shapeInfo = new ShapeInfoInfo();
133 }
134
135 // Get another reference to this shape.
136 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
137
138 // Called when this shape is being used again.
139 // Used internally. External callers should call instance.GetReference() to properly copy/reference
140 // the shape.
141 protected virtual void IncrementReference()
142 {
143 referenceCount++;
144 lastReferenced = DateTime.Now;
145 }
146
147 // Called when this shape is done being used.
148 protected virtual void DecrementReference()
149 {
150 referenceCount--;
151 lastReferenced = DateTime.Now;
152 }
153
154 // Release the use of a physical shape.
155 public abstract void Dereference(BSScene physicsScene);
156
157 // Return 'true' if there is an allocated physics physical shape under this class instance.
158 public virtual bool HasPhysicalShape
159 {
160 get
161 {
162 if (physShapeInfo != null)
163 return physShapeInfo.HasPhysicalShape;
164 return false;
165 }
166 }
167 public virtual BSPhysicsShapeType ShapeType
168 {
169 get
170 {
171 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
172 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
173 ret = physShapeInfo.shapeType;
174 return ret;
175 }
176 }
177
178 // Returns a string for debugging that uniquily identifies the memory used by this instance
179 public virtual string AddrString
180 {
181 get
182 {
183 if (physShapeInfo != null)
184 return physShapeInfo.AddrString;
185 return "unknown";
186 }
187 }
188
189 public override string ToString()
190 {
191 StringBuilder buff = new StringBuilder();
192 if (physShapeInfo == null)
193 {
194 buff.Append("<noPhys");
195 }
196 else
197 {
198 buff.Append("<phy=");
199 buff.Append(physShapeInfo.ToString());
200 }
201 buff.Append(",c=");
202 buff.Append(referenceCount.ToString());
203 buff.Append(">");
204 return buff.ToString();
205 }
206
207 #region Common shape routines
208 // Create a hash of all the shape parameters to be used as a key for this particular shape.
209 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
210 {
211 // level of detail based on size and type of the object
212 float lod = BSParam.MeshLOD;
213 if (pbs.SculptEntry)
214 lod = BSParam.SculptLOD;
215
216 // Mega prims usually get more detail because one can interact with shape approximations at this size.
217 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
218 if (maxAxis > BSParam.MeshMegaPrimThreshold)
219 lod = BSParam.MeshMegaPrimLOD;
220
221 retLod = lod;
222 return pbs.GetMeshKey(size, lod);
223 }
224
225 // The creation of a mesh or hull can fail if an underlying asset is not available.
226 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
227 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
228 // The first case causes the asset to be fetched. The second case requires
229 // us to not loop forever.
230 // Called after creating a physical mesh or hull. If the physical shape was created,
231 // just return.
232 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
233 {
234 // If the shape was successfully created, nothing more to do
235 if (newShape.HasPhysicalShape)
236 return newShape;
237
238 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
239 // fetched but we end up here again, the meshing of the asset must have failed.
240 // Prevent trying to keep fetching the mesh by declaring failure.
241 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
242 {
243 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
244 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}",
245 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
246 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}",
247 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
248 }
249 else
250 {
251 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
252 if (prim.BaseShape.SculptEntry
253 && !prim.AssetFailed()
254 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
255 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
256 )
257 {
258 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
259 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
260 // Multiple requestors will know we're waiting for this asset
261 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
262
263 BSPhysObject xprim = prim;
264 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
265 if (assetProvider != null)
266 {
267 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
268 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
269 {
270 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
271 bool assetFound = false;
272 string mismatchIDs = String.Empty; // DEBUG DEBUG
273 if (asset != null && yprim.BaseShape.SculptEntry)
274 {
275 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
276 {
277 yprim.BaseShape.SculptData = asset.Data;
278 // This will cause the prim to see that the filler shape is not the right
279 // one and try again to build the object.
280 // No race condition with the normal shape setting since the rebuild is at taint time.
281 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
282 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
283 assetFound = true;
284 }
285 else
286 {
287 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
288 }
289 }
290 if (!assetFound)
291 {
292 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
293 }
294 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
295 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
296 });
297 }
298 else
299 {
300 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
301 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
302 LogHeader, physicsScene.Name);
303 }
304 }
305 else
306 {
307 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
308 {
309 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}",
310 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
311 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}",
312 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
313 }
314 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing)
315 {
316 physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}",
317 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
318 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}",
319 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
320 }
321 }
322 }
323
324 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
325 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
326 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
327
328 return fillShape.physShapeInfo;
329 }
330
331 public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim)
332 {
333 StringBuilder buff = new StringBuilder(prim.PhysObjectName);
334 buff.Append("/pos=");
335 buff.Append(prim.RawPosition.ToString());
336 if (pScene != null)
337 {
338 buff.Append("/rgn=");
339 buff.Append(pScene.Name);
340 }
341 return buff.ToString();
342 }
343
344 #endregion // Common shape routines
345}
346
347// ============================================================================================================
348public class BSShapeNull : BSShape
349{
350 public BSShapeNull() : base()
351 {
352 }
353 public static BSShape GetReference() { return new BSShapeNull(); }
354 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
355 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
356}
357
358// ============================================================================================================
359// BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere.
360// They are odd in that they don't allocate meshes but are computated/procedural.
361// This means allocation and freeing is different than meshes.
362public class BSShapeNative : BSShape
363{
364 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
365 public BSShapeNative(BulletShape pShape) : base(pShape)
366 {
367 }
368
369 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
370 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
371 {
372 // Native shapes are not shared and are always built anew.
373 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
374 }
375
376 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
377 {
378 // Native shapes are not shared so we return a new shape.
379 BSShape ret = null;
380 lock (physShapeInfo)
381 {
382 ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
383 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
384 }
385 return ret;
386 }
387
388 // Make this reference to the physical shape go away since native shapes are not shared.
389 public override void Dereference(BSScene physicsScene)
390 {
391 // Native shapes are not tracked and are released immediately
392 lock (physShapeInfo)
393 {
394 if (physShapeInfo.HasPhysicalShape)
395 {
396 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
397 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
398 }
399 physShapeInfo.Clear();
400 // Garbage collection will free up this instance.
401 }
402 }
403
404 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
405 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
406 {
407 BulletShape newShape;
408
409 ShapeData nativeShapeData = new ShapeData();
410 nativeShapeData.Type = shapeType;
411 nativeShapeData.ID = prim.LocalID;
412 nativeShapeData.Scale = prim.Scale;
413 nativeShapeData.Size = prim.Scale;
414 nativeShapeData.MeshKey = (ulong)shapeKey;
415 nativeShapeData.HullKey = (ulong)shapeKey;
416
417 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
418 {
419 newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
420 physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
421 }
422 else
423 {
424 newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
425 }
426 if (!newShape.HasPhysicalShape)
427 {
428 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
429 LogHeader, prim.LocalID, shapeType);
430 }
431 newShape.shapeType = shapeType;
432 newShape.isNativeShape = true;
433 newShape.shapeKey = (UInt64)shapeKey;
434 return newShape;
435 }
436
437}
438
439// ============================================================================================================
440// BSShapeMesh is a simple mesh.
441public class BSShapeMesh : BSShape
442{
443 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
444 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
445
446 public BSShapeMesh(BulletShape pShape) : base(pShape)
447 {
448 }
449 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
450 {
451 float lod;
452 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
453
454 BSShapeMesh retMesh = null;
455 lock (Meshes)
456 {
457 if (Meshes.TryGetValue(newMeshKey, out retMesh))
458 {
459 // The mesh has already been created. Return a new reference to same.
460 retMesh.IncrementReference();
461 }
462 else
463 {
464 retMesh = new BSShapeMesh(new BulletShape());
465 // An instance of this mesh has not been created. Build and remember same.
466 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
467
468 // Check to see if mesh was created (might require an asset).
469 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
470 if (!newShape.isNativeShape || prim.AssetFailed() )
471 {
472 // If a mesh was what was created, remember the built shape for later sharing.
473 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
474 Meshes.Add(newMeshKey, retMesh);
475 }
476
477 retMesh.physShapeInfo = newShape;
478 }
479 }
480 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
481 return retMesh;
482 }
483 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
484 {
485 BSShape ret = null;
486 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
487 // and we must create a copy of the native shape since they are never shared.
488 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
489 {
490 // TODO: decide when the native shapes should be freed. Check in Dereference?
491 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
492 }
493 else
494 {
495 // Another reference to this shape is just counted.
496 IncrementReference();
497 ret = this;
498 }
499 return ret;
500 }
501 public override void Dereference(BSScene physicsScene)
502 {
503 lock (Meshes)
504 {
505 this.DecrementReference();
506 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
507 // TODO: schedule aging and destruction of unused meshes.
508 }
509 }
510 // Loop through all the known meshes and return the description based on the physical address.
511 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
512 {
513 bool ret = false;
514 BSShapeMesh foundDesc = null;
515 lock (Meshes)
516 {
517 foreach (BSShapeMesh sm in Meshes.Values)
518 {
519 if (sm.physShapeInfo.ReferenceSame(pShape))
520 {
521 foundDesc = sm;
522 ret = true;
523 break;
524 }
525
526 }
527 }
528 outMesh = foundDesc;
529 return ret;
530 }
531
532 public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
533 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
534 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
535 {
536 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
537 (w, iC, i, vC, v) =>
538 {
539 shapeInfo.Vertices = vC;
540 return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v);
541 });
542 }
543
544 // Code that uses the mesher to create the index/vertices info for a trimesh shape.
545 // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
546 // The actual build call is passed so this logic can be used by several of the shapes that use a
547 // simple mesh as their base shape.
548 public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
549 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
550 {
551 BulletShape newShape = new BulletShape();
552
553 IMesh meshData = null;
554 lock (physicsScene.mesher)
555 {
556 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
557 false, // say it is not physical so a bounding box is not built
558 false // do not cache the mesh and do not use previously built versions
559 );
560 }
561
562 if (meshData != null)
563 {
564 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
565 {
566 // Release the fetched asset data once it has been used.
567 pbs.SculptData = new byte[0];
568 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
569 }
570
571 int[] indices = meshData.getIndexListAsInt();
572 int realIndicesIndex = indices.Length;
573 float[] verticesAsFloats = meshData.getVertexListAsFloat();
574
575 if (BSParam.ShouldRemoveZeroWidthTriangles)
576 {
577 // Remove degenerate triangles. These are triangles with two of the vertices
578 // are the same. This is complicated by the problem that vertices are not
579 // made unique in sculpties so we have to compare the values in the vertex.
580 realIndicesIndex = 0;
581 for (int tri = 0; tri < indices.Length; tri += 3)
582 {
583 // Compute displacements into vertex array for each vertex of the triangle
584 int v1 = indices[tri + 0] * 3;
585 int v2 = indices[tri + 1] * 3;
586 int v3 = indices[tri + 2] * 3;
587 // Check to see if any two of the vertices are the same
588 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
589 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
590 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
591 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
592 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
593 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
594 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
595 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
596 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
597 )
598 {
599 // None of the vertices of the triangles are the same. This is a good triangle;
600 indices[realIndicesIndex + 0] = indices[tri + 0];
601 indices[realIndicesIndex + 1] = indices[tri + 1];
602 indices[realIndicesIndex + 2] = indices[tri + 2];
603 realIndicesIndex += 3;
604 }
605 }
606 }
607 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
608 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
609
610 if (realIndicesIndex != 0)
611 {
612 newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
613 }
614 else
615 {
616 // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
617 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
618 physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) );
619 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
620 }
621 }
622 newShape.shapeKey = newMeshKey;
623
624 return newShape;
625 }
626}
627
628// ============================================================================================================
629// BSShapeHull is a physical shape representation htat is made up of many convex hulls.
630// The convex hulls are either supplied with the asset or are approximated by one of the
631// convex hull creation routines (in OpenSim or in Bullet).
632public class BSShapeHull : BSShape
633{
634#pragma warning disable 414
635 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
636#pragma warning restore 414
637
638 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
639
640
641 public BSShapeHull(BulletShape pShape) : base(pShape)
642 {
643 }
644 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
645 {
646 float lod;
647 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
648
649 BSShapeHull retHull = null;
650 lock (Hulls)
651 {
652 if (Hulls.TryGetValue(newHullKey, out retHull))
653 {
654 // The mesh has already been created. Return a new reference to same.
655 retHull.IncrementReference();
656 }
657 else
658 {
659 retHull = new BSShapeHull(new BulletShape());
660 // An instance of this mesh has not been created. Build and remember same.
661 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
662
663 // Check to see if hull was created (might require an asset).
664 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
665 if (!newShape.isNativeShape || prim.AssetFailed())
666 {
667 // If a mesh was what was created, remember the built shape for later sharing.
668 Hulls.Add(newHullKey, retHull);
669 }
670 retHull.physShapeInfo = newShape;
671 }
672 }
673 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
674 return retHull;
675 }
676 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
677 {
678 BSShape ret = null;
679 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
680 // and we must create a copy of the native shape since they are never shared.
681 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
682 {
683 // TODO: decide when the native shapes should be freed. Check in Dereference?
684 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
685 }
686 else
687 {
688 // Another reference to this shape is just counted.
689 IncrementReference();
690 ret = this;
691 }
692 return ret;
693 }
694 public override void Dereference(BSScene physicsScene)
695 {
696 lock (Hulls)
697 {
698 this.DecrementReference();
699 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
700 // TODO: schedule aging and destruction of unused meshes.
701 }
702 }
703
704 List<ConvexResult> m_hulls;
705 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
706 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
707 {
708 BulletShape newShape = new BulletShape();
709
710 IMesh meshData = null;
711 List<List<OMV.Vector3>> allHulls = null;
712 lock (physicsScene.mesher)
713 {
714 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
715 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
716
717 // If we should use the asset's hull info, fetch it out of the locked mesher
718 if (meshData != null && BSParam.ShouldUseAssetHulls)
719 {
720 Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
721 if (realMesher != null)
722 {
723 allHulls = realMesher.GetConvexHulls(size);
724 }
725 if (allHulls == null)
726 {
727 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
728 }
729 }
730 }
731
732 // If there is hull data in the mesh asset, build the hull from that
733 if (allHulls != null && BSParam.ShouldUseAssetHulls)
734 {
735 int hullCount = allHulls.Count;
736 shapeInfo.HullCount = hullCount;
737 int totalVertices = 1; // include one for the count of the hulls
738 // Using the structure described for HACD hulls, create the memory sturcture
739 // to pass the hull data to the creater.
740 foreach (List<OMV.Vector3> hullVerts in allHulls)
741 {
742 totalVertices += 4; // add four for the vertex count and centroid
743 totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
744 }
745 float[] convHulls = new float[totalVertices];
746
747 convHulls[0] = (float)hullCount;
748 int jj = 1;
749 int hullIndex = 0;
750 foreach (List<OMV.Vector3> hullVerts in allHulls)
751 {
752 convHulls[jj + 0] = hullVerts.Count;
753 convHulls[jj + 1] = 0f; // centroid x,y,z
754 convHulls[jj + 2] = 0f;
755 convHulls[jj + 3] = 0f;
756 jj += 4;
757 foreach (OMV.Vector3 oneVert in hullVerts)
758 {
759 convHulls[jj + 0] = oneVert.X;
760 convHulls[jj + 1] = oneVert.Y;
761 convHulls[jj + 2] = oneVert.Z;
762 jj += 3;
763 }
764 shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count);
765 hullIndex++;
766 }
767
768 // create the hull data structure in Bullet
769 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
770
771 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
772 prim.LocalID, hullCount, totalVertices, newShape);
773 }
774
775 // If no hull specified in the asset and we should use Bullet's HACD approximation...
776 if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
777 {
778 // Build the hull shape from an existing mesh shape.
779 // The mesh should have already been created in Bullet.
780 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
781 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
782
783 if (meshShape.physShapeInfo.HasPhysicalShape)
784 {
785 HACDParams parms = new HACDParams();
786 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
787 parms.minClusters = BSParam.BHullMinClusters;
788 parms.compacityWeight = BSParam.BHullCompacityWeight;
789 parms.volumeWeight = BSParam.BHullVolumeWeight;
790 parms.concavity = BSParam.BHullConcavity;
791 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
792 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
793 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
794 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
795 parms.whichHACD = 0; // Use the HACD routine that comes with Bullet
796
797 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
798 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
799 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
800
801 // Now done with the mesh shape.
802 shapeInfo.HullCount = 1;
803 BSShapeMesh maybeMesh = meshShape as BSShapeMesh;
804 if (maybeMesh != null)
805 shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices);
806 meshShape.Dereference(physicsScene);
807 }
808 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
809 }
810
811 // If no other hull specifications, use our HACD hull approximation.
812 if (!newShape.HasPhysicalShape && meshData != null)
813 {
814 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
815 {
816 // Release the fetched asset data once it has been used.
817 pbs.SculptData = new byte[0];
818 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
819 }
820
821 int[] indices = meshData.getIndexListAsInt();
822 List<OMV.Vector3> vertices = meshData.getVertexList();
823
824 //format conversion from IMesh format to DecompDesc format
825 List<int> convIndices = new List<int>();
826 List<float3> convVertices = new List<float3>();
827 for (int ii = 0; ii < indices.GetLength(0); ii++)
828 {
829 convIndices.Add(indices[ii]);
830 }
831 foreach (OMV.Vector3 vv in vertices)
832 {
833 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
834 }
835
836 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
837 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
838 {
839 // Simple primitive shapes we know are convex so they are better implemented with
840 // fewer hulls.
841 // Check for simple shape (prim without cuts) and reduce split parameter if so.
842 if (BSShapeCollection.PrimHasNoCuts(pbs))
843 {
844 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
845 }
846 }
847
848 // setup and do convex hull conversion
849 m_hulls = new List<ConvexResult>();
850 DecompDesc dcomp = new DecompDesc();
851 dcomp.mIndices = convIndices;
852 dcomp.mVertices = convVertices;
853 dcomp.mDepth = maxDepthSplit;
854 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
855 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
856 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
857 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
858 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
859 // create the hull into the _hulls variable
860 convexBuilder.process(dcomp);
861
862 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
863 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
864
865 // Convert the vertices and indices for passing to unmanaged.
866 // The hull information is passed as a large floating point array.
867 // The format is:
868 // convHulls[0] = number of hulls
869 // convHulls[1] = number of vertices in first hull
870 // convHulls[2] = hull centroid X coordinate
871 // convHulls[3] = hull centroid Y coordinate
872 // convHulls[4] = hull centroid Z coordinate
873 // convHulls[5] = first hull vertex X
874 // convHulls[6] = first hull vertex Y
875 // convHulls[7] = first hull vertex Z
876 // convHulls[8] = second hull vertex X
877 // ...
878 // convHulls[n] = number of vertices in second hull
879 // convHulls[n+1] = second hull centroid X coordinate
880 // ...
881 //
882 // TODO: is is very inefficient. Someday change the convex hull generator to return
883 // data structures that do not need to be converted in order to pass to Bullet.
884 // And maybe put the values directly into pinned memory rather than marshaling.
885 int hullCount = m_hulls.Count;
886 int totalVertices = 1; // include one for the count of the hulls
887 foreach (ConvexResult cr in m_hulls)
888 {
889 totalVertices += 4; // add four for the vertex count and centroid
890 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
891 }
892 float[] convHulls = new float[totalVertices];
893
894 convHulls[0] = (float)hullCount;
895 int jj = 1;
896 foreach (ConvexResult cr in m_hulls)
897 {
898 // copy vertices for index access
899 float3[] verts = new float3[cr.HullVertices.Count];
900 int kk = 0;
901 foreach (float3 ff in cr.HullVertices)
902 {
903 verts[kk++] = ff;
904 }
905
906 // add to the array one hull's worth of data
907 convHulls[jj++] = cr.HullIndices.Count;
908 convHulls[jj++] = 0f; // centroid x,y,z
909 convHulls[jj++] = 0f;
910 convHulls[jj++] = 0f;
911 foreach (int ind in cr.HullIndices)
912 {
913 convHulls[jj++] = verts[ind].x;
914 convHulls[jj++] = verts[ind].y;
915 convHulls[jj++] = verts[ind].z;
916 }
917 }
918 // create the hull data structure in Bullet
919 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
920 }
921 newShape.shapeKey = newHullKey;
922 return newShape;
923 }
924 // Callback from convex hull creater with a newly created hull.
925 // Just add it to our collection of hulls for this shape.
926 private void HullReturn(ConvexResult result)
927 {
928 m_hulls.Add(result);
929 return;
930 }
931 // Loop through all the known hulls and return the description based on the physical address.
932 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
933 {
934 bool ret = false;
935 BSShapeHull foundDesc = null;
936 lock (Hulls)
937 {
938 foreach (BSShapeHull sh in Hulls.Values)
939 {
940 if (sh.physShapeInfo.ReferenceSame(pShape))
941 {
942 foundDesc = sh;
943 ret = true;
944 break;
945 }
946
947 }
948 }
949 outHull = foundDesc;
950 return ret;
951 }
952}
953
954// ============================================================================================================
955// BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate
956// meshes. Used by BulletSim for complex shapes like linksets.
957public class BSShapeCompound : BSShape
958{
959 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
960 public static Dictionary<string, BSShapeCompound> CompoundShapes = new Dictionary<string, BSShapeCompound>();
961
962 public BSShapeCompound(BulletShape pShape) : base(pShape)
963 {
964 }
965 public static BSShape GetReference(BSScene physicsScene)
966 {
967 // Base compound shapes are not shared so this returns a raw shape.
968 // A built compound shape can be reused in linksets.
969 BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
970 CompoundShapes.Add(ret.AddrString, ret);
971 return ret;
972 }
973 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
974 {
975 // Calling this reference means we want another handle to an existing compound shape
976 // (usually linksets) so return this copy.
977 IncrementReference();
978 return this;
979 }
980 // Dereferencing a compound shape releases the hold on all the child shapes.
981 public override void Dereference(BSScene physicsScene)
982 {
983 lock (physShapeInfo)
984 {
985 this.DecrementReference();
986 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
987 if (referenceCount <= 0)
988 {
989 if (!physicsScene.PE.IsCompound(physShapeInfo))
990 {
991 // Failed the sanity check!!
992 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
993 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
994 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
995 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
996 return;
997 }
998
999 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
1000 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
1001 BSScene.DetailLogZero, physShapeInfo, numChildren);
1002
1003 // Loop through all the children dereferencing each.
1004 for (int ii = numChildren - 1; ii >= 0; ii--)
1005 {
1006 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
1007 DereferenceAnonCollisionShape(physicsScene, childShape);
1008 }
1009
1010 lock (CompoundShapes)
1011 CompoundShapes.Remove(physShapeInfo.AddrString);
1012 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
1013 }
1014 }
1015 }
1016 public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound)
1017 {
1018 lock (CompoundShapes)
1019 {
1020 string addr = pShape.AddrString;
1021 return CompoundShapes.TryGetValue(addr, out outCompound);
1022 }
1023 }
1024 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
1025 {
1026 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
1027 return cShape;
1028 }
1029 // Sometimes we have a pointer to a collision shape but don't know what type it is.
1030 // Figure out type and call the correct dereference routine.
1031 // Called at taint-time.
1032 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
1033 {
1034 // TODO: figure a better way to go through all the shape types and find a possible instance.
1035 physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}",
1036 BSScene.DetailLogZero, pShape);
1037 BSShapeMesh meshDesc;
1038 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
1039 {
1040 meshDesc.Dereference(physicsScene);
1041 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape);
1042 }
1043 else
1044 {
1045 BSShapeHull hullDesc;
1046 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
1047 {
1048 hullDesc.Dereference(physicsScene);
1049 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape);
1050 }
1051 else
1052 {
1053 BSShapeConvexHull chullDesc;
1054 if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc))
1055 {
1056 chullDesc.Dereference(physicsScene);
1057 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape);
1058 }
1059 else
1060 {
1061 BSShapeGImpact gImpactDesc;
1062 if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
1063 {
1064 gImpactDesc.Dereference(physicsScene);
1065 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape);
1066 }
1067 else
1068 {
1069 // Didn't find it in the lists of specific types. It could be compound.
1070 BSShapeCompound compoundDesc;
1071 if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc))
1072 {
1073 compoundDesc.Dereference(physicsScene);
1074 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape);
1075 }
1076 else
1077 {
1078 // If none of the above, maybe it is a simple native shape.
1079 if (physicsScene.PE.IsNativeShape(pShape))
1080 {
1081 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape);
1082 BSShapeNative nativeShape = new BSShapeNative(pShape);
1083 nativeShape.Dereference(physicsScene);
1084 }
1085 else
1086 {
1087 physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}",
1088 LogHeader, pShape);
1089 }
1090 }
1091 }
1092 }
1093 }
1094 }
1095 }
1096}
1097
1098// ============================================================================================================
1099// BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex
1100// hull shapes. This is used for simple prims that are convex and thus can be made into a simple
1101// collision shape (a single hull). More complex physical shapes will be BSShapeHull's.
1102public class BSShapeConvexHull : BSShape
1103{
1104#pragma warning disable 414
1105 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
1106#pragma warning restore 414
1107
1108 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
1109
1110 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
1111 {
1112 }
1113 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1114 {
1115 float lod;
1116 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1117
1118 physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
1119 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1120
1121 BSShapeConvexHull retConvexHull = null;
1122 lock (ConvexHulls)
1123 {
1124 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
1125 {
1126 // The mesh has already been created. Return a new reference to same.
1127 retConvexHull.IncrementReference();
1128 }
1129 else
1130 {
1131 retConvexHull = new BSShapeConvexHull(new BulletShape());
1132 BulletShape convexShape = null;
1133
1134 // Get a handle to a mesh to build the hull from
1135 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
1136 if (baseMesh.physShapeInfo.isNativeShape)
1137 {
1138 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
1139 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
1140 // get back to this code with a buildable mesh.
1141 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
1142 convexShape = baseMesh.physShapeInfo;
1143 }
1144 else
1145 {
1146 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
1147 convexShape.shapeKey = newMeshKey;
1148 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
1149 physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}",
1150 BSScene.DetailLogZero, convexShape);
1151 }
1152
1153 // Done with the base mesh
1154 baseMesh.Dereference(physicsScene);
1155
1156 retConvexHull.physShapeInfo = convexShape;
1157 }
1158 }
1159 return retConvexHull;
1160 }
1161 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
1162 {
1163 // Calling this reference means we want another handle to an existing shape
1164 // (usually linksets) so return this copy.
1165 IncrementReference();
1166 return this;
1167 }
1168 // Dereferencing a compound shape releases the hold on all the child shapes.
1169 public override void Dereference(BSScene physicsScene)
1170 {
1171 lock (ConvexHulls)
1172 {
1173 this.DecrementReference();
1174 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
1175 // TODO: schedule aging and destruction of unused meshes.
1176 }
1177 }
1178 // Loop through all the known hulls and return the description based on the physical address.
1179 public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
1180 {
1181 bool ret = false;
1182 BSShapeConvexHull foundDesc = null;
1183 lock (ConvexHulls)
1184 {
1185 foreach (BSShapeConvexHull sh in ConvexHulls.Values)
1186 {
1187 if (sh.physShapeInfo.ReferenceSame(pShape))
1188 {
1189 foundDesc = sh;
1190 ret = true;
1191 break;
1192 }
1193
1194 }
1195 }
1196 outHull = foundDesc;
1197 return ret;
1198 }
1199}
1200// ============================================================================================================
1201// BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that
1202// can handle concave as well as convex shapes. Much slower computationally but creates smoother
1203// shapes than multiple convex hull approximations.
1204public class BSShapeGImpact : BSShape
1205{
1206#pragma warning disable 414
1207 private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
1208#pragma warning restore 414
1209
1210 public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
1211
1212 public BSShapeGImpact(BulletShape pShape) : base(pShape)
1213 {
1214 }
1215 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1216 {
1217 float lod;
1218 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1219
1220 physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
1221 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1222
1223 BSShapeGImpact retGImpact = null;
1224 lock (GImpacts)
1225 {
1226 if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
1227 {
1228 // The mesh has already been created. Return a new reference to same.
1229 retGImpact.IncrementReference();
1230 }
1231 else
1232 {
1233 retGImpact = new BSShapeGImpact(new BulletShape());
1234 BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
1235
1236 // Check to see if mesh was created (might require an asset).
1237 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
1238 newShape.shapeKey = newMeshKey;
1239 if (!newShape.isNativeShape || prim.AssetFailed())
1240 {
1241 // If a mesh was what was created, remember the built shape for later sharing.
1242 // Also note that if meshing failed we put it in the mesh list as there is nothing
1243 // else to do about the mesh.
1244 GImpacts.Add(newMeshKey, retGImpact);
1245 }
1246
1247 retGImpact.physShapeInfo = newShape;
1248 }
1249 }
1250 return retGImpact;
1251 }
1252
1253 private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
1254 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
1255 {
1256 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
1257 (w, iC, i, vC, v) =>
1258 {
1259 shapeInfo.Vertices = vC;
1260 return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v);
1261 });
1262 }
1263
1264 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1265 {
1266 BSShape ret = null;
1267 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
1268 // and we must create a copy of the native shape since they are never shared.
1269 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
1270 {
1271 // TODO: decide when the native shapes should be freed. Check in Dereference?
1272 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1273 }
1274 else
1275 {
1276 // Another reference to this shape is just counted.
1277 IncrementReference();
1278 ret = this;
1279 }
1280 return ret;
1281 }
1282 // Dereferencing a compound shape releases the hold on all the child shapes.
1283 public override void Dereference(BSScene physicsScene)
1284 {
1285 lock (GImpacts)
1286 {
1287 this.DecrementReference();
1288 physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
1289 // TODO: schedule aging and destruction of unused meshes.
1290 }
1291 }
1292 // Loop through all the known hulls and return the description based on the physical address.
1293 public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
1294 {
1295 bool ret = false;
1296 BSShapeGImpact foundDesc = null;
1297 lock (GImpacts)
1298 {
1299 foreach (BSShapeGImpact sh in GImpacts.Values)
1300 {
1301 if (sh.physShapeInfo.ReferenceSame(pShape))
1302 {
1303 foundDesc = sh;
1304 ret = true;
1305 break;
1306 }
1307
1308 }
1309 }
1310 outHull = foundDesc;
1311 return ret;
1312 }
1313}
1314
1315// ============================================================================================================
1316// BSShapeAvatar is a specialized mesh shape for avatars.
1317public class BSShapeAvatar : BSShape
1318{
1319#pragma warning disable 414
1320 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
1321#pragma warning restore 414
1322
1323 public BSShapeAvatar()
1324 : base()
1325 {
1326 }
1327 public static BSShape GetReference(BSPhysObject prim)
1328 {
1329 return new BSShapeNull();
1330 }
1331 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1332 {
1333 return new BSShapeNull();
1334 }
1335 public override void Dereference(BSScene physicsScene) { }
1336
1337 // From the front:
1338 // A---A
1339 // / \
1340 // B-------B
1341 // / \ +Z
1342 // C-----------C |
1343 // \ / -Y --+-- +Y
1344 // \ / |
1345 // \ / -Z
1346 // D-----D
1347 // \ /
1348 // E-E
1349
1350 // From the top A and E are just lines.
1351 // B, C and D are hexagons:
1352 //
1353 // C1--C2 +X
1354 // / \ |
1355 // C0 C3 -Y --+-- +Y
1356 // \ / |
1357 // C5--C4 -X
1358
1359 // Zero goes directly through the middle so the offsets are from that middle axis
1360 // and up and down from a middle horizon (A and E are the same distance from the zero).
1361 // The height, width and depth is one. All scaling is done by the simulator.
1362
1363 // Z component -- how far the level is from the middle zero
1364 private const float Aup = 0.5f;
1365 private const float Bup = 0.4f;
1366 private const float Cup = 0.3f;
1367 private const float Dup = -0.4f;
1368 private const float Eup = -0.5f;
1369
1370 // Y component -- distance from center to x0 and x3
1371 private const float Awid = 0.25f;
1372 private const float Bwid = 0.3f;
1373 private const float Cwid = 0.5f;
1374 private const float Dwid = 0.3f;
1375 private const float Ewid = 0.2f;
1376
1377 // Y component -- distance from center to x1, x2, x4 and x5
1378 private const float Afwid = 0.0f;
1379 private const float Bfwid = 0.2f;
1380 private const float Cfwid = 0.4f;
1381 private const float Dfwid = 0.2f;
1382 private const float Efwid = 0.0f;
1383
1384 // X component -- distance from zero to the front or back of a level
1385 private const float Adep = 0f;
1386 private const float Bdep = 0.3f;
1387 private const float Cdep = 0.5f;
1388 private const float Ddep = 0.2f;
1389 private const float Edep = 0f;
1390
1391 private OMV.Vector3[] avatarVertices = {
1392 new OMV.Vector3( 0.0f, -Awid, Aup), // A0
1393 new OMV.Vector3( 0.0f, +Awid, Aup), // A3
1394
1395 new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
1396 new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
1397 new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
1398 new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
1399 new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
1400 new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
1401
1402 new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
1403 new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
1404 new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
1405 new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
1406 new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
1407 new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
1408
1409 new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
1410 new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
1411 new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
1412 new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
1413 new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
1414 new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
1415
1416 new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
1417 new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
1418 };
1419
1420 // Offsets of the vertices in the vertices array
1421 private enum Ind : int
1422 {
1423 A0, A3,
1424 B0, B1, B2, B3, B4, B5,
1425 C0, C1, C2, C3, C4, C5,
1426 D0, D1, D2, D3, D4, D5,
1427 E0, E3
1428 }
1429
1430 // Comments specify trianges and quads in clockwise direction
1431 private Ind[] avatarIndices = {
1432 Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
1433 Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
1434 Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
1435 Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
1436 Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
1437 Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
1438
1439 Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
1440 Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
1441 Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
1442 Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
1443 Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
1444 Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
1445
1446 Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
1447 Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
1448 Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
1449 Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
1450 Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
1451 Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
1452
1453 Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
1454 Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
1455 Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
1456 Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
1457 Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
1458 Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
1459
1460 };
1461
1462}
1463}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
new file mode 100755
index 0000000..d70b2fb
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
@@ -0,0 +1,170 @@
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.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHMapInfo m_mapInfo = null;
48
49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
51 : base(physicsScene, regionBase, id)
52 {
53 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
54 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
55 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
56 float[] initialMap = new float[totalHeights];
57 for (int ii = 0; ii < totalHeights; ii++)
58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 }
61 m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y);
62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase;
65 // Don't have to free any previous since we just got here.
66 BuildHeightmapTerrain();
67 }
68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id)
74 {
75 m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y);
76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z;
79 m_mapInfo.maxZ = maxCoords.Z;
80 m_mapInfo.terrainRegionBase = TerrainBase;
81
82 // Don't have to free any previous since we just got here.
83 BuildHeightmapTerrain();
84 }
85
86 public override void Dispose()
87 {
88 ReleaseHeightMapTerrain();
89 }
90
91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain()
93 {
94 // Create the terrain shape from the mapInfo
95 m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98
99
100 // The terrain object initial position is at the center of the object
101 Vector3 centerPos;
102 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
105
106 m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
107 m_mapInfo.ID, centerPos, Quaternion.Identity);
108
109 // Set current terrain attributes
110 m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
111 m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
112 m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
113 m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
114
115 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
116
117 // Return the new terrain to the world of physical objects
118 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
119
120 // redo its bounding box now that it is in the world
121 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
122
123 // Make it so the terrain will not move or be considered for movement.
124 m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
125
126 return;
127 }
128
129 // If there is information in m_mapInfo pointing to physical structures, release same.
130 private void ReleaseHeightMapTerrain()
131 {
132 if (m_mapInfo != null)
133 {
134 if (m_mapInfo.terrainBody.HasPhysicalBody)
135 {
136 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
137 // Frees both the body and the shape.
138 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
139 }
140 }
141 m_mapInfo = null;
142 }
143
144 // The passed position is relative to the base of the region.
145 public override float GetTerrainHeightAtXYZ(Vector3 pos)
146 {
147 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
148
149 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
150 try
151 {
152 ret = m_mapInfo.heightMap[mapIndex];
153 }
154 catch
155 {
156 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
157 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
158 LogHeader, m_mapInfo.terrainRegionBase, pos);
159 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
160 }
161 return ret;
162 }
163
164 // The passed position is relative to the base of the region.
165 public override float GetWaterLevelAtXYZ(Vector3 pos)
166 {
167 return m_physicsScene.SimpleWaterLevel;
168 }
169}
170}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
new file mode 100755
index 0000000..50f917a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
@@ -0,0 +1,585 @@
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.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43
44// The physical implementation of the terrain is wrapped in this class.
45public abstract class BSTerrainPhys : IDisposable
46{
47 public enum TerrainImplementation
48 {
49 Heightmap = 0,
50 Mesh = 1
51 }
52
53 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; }
57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 {
60 m_physicsScene = physicsScene;
61 TerrainBase = regionBase;
62 ID = id;
63 }
64 public abstract void Dispose();
65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
67}
68
69// ==========================================================================================
70public sealed class BSTerrainManager : IDisposable
71{
72 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
73
74 // These height values are fractional so the odd values will be
75 // noticable when debugging.
76 public const float HEIGHT_INITIALIZATION = 24.987f;
77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
80
81 // If the min and max height are equal, we reduce the min by this
82 // amount to make sure that a bounding box is built for the terrain.
83 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
84
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);
87
88 // The scene that I am part of
89 private BSScene m_physicsScene { get; set; }
90
91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane;
93
94 // If doing mega-regions, if we're region zero we will be managing multiple
95 // region terrains since region zero does the physics for the whole mega-region.
96 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
97
98 // Flags used to know when to recalculate the height.
99 private bool m_terrainModified = false;
100
101 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
102 // This is incremented before assigning to new region so it is the last ID allocated.
103 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
104 public uint HighestTerrainID { get {return m_terrainCount; } }
105
106 // If doing mega-regions, this holds our offset from region zero of
107 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
108 private Vector3 m_worldOffset;
109 // If the parent region (region 0), this is the extent of the combined regions
110 // relative to the origin of region zero
111 private Vector3 m_worldMax;
112 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
113
114 public BSTerrainManager(BSScene physicsScene, Vector3 regionSize)
115 {
116 m_physicsScene = physicsScene;
117 DefaultRegionSize = regionSize;
118
119 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
120
121 // Assume one region of default size
122 m_worldOffset = Vector3.Zero;
123 m_worldMax = new Vector3(DefaultRegionSize);
124 MegaRegionParentPhysicsScene = null;
125 }
126
127 public void Dispose()
128 {
129 ReleaseGroundPlaneAndTerrain();
130 }
131
132 // Create the initial instance of terrain and the underlying ground plane.
133 // This is called from the initialization routine so we presume it is
134 // safe to call Bullet in real time. We hope no one is moving prims around yet.
135 public void CreateInitialGroundPlaneAndTerrain()
136 {
137 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
138 // The ground plane is here to catch things that are trying to drop to negative infinity
139 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
140 Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane);
141 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
142 BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity);
143
144 // Everything collides with the ground plane.
145 m_groundPlane.collisionType = CollisionType.Groundplane;
146
147 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
148 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
149
150 // Ground plane does not move
151 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
152
153 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
154 lock (m_terrains)
155 {
156 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
157 m_terrains.Add(Vector3.Zero, initialTerrain);
158 }
159 }
160
161 // Release all the terrain structures we might have allocated
162 public void ReleaseGroundPlaneAndTerrain()
163 {
164 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
165 if (m_groundPlane.HasPhysicalBody)
166 {
167 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
168 {
169 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
170 }
171 m_groundPlane.Clear();
172 }
173
174 ReleaseTerrain();
175 }
176
177 // Release all the terrain we have allocated
178 public void ReleaseTerrain()
179 {
180 lock (m_terrains)
181 {
182 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
183 {
184 kvp.Value.Dispose();
185 }
186 m_terrains.Clear();
187 }
188 }
189
190 // The simulator wants to set a new heightmap for the terrain.
191 public void SetTerrain(float[] heightMap) {
192 float[] localHeightMap = heightMap;
193 // If there are multiple requests for changes to the same terrain between ticks,
194 // only do that last one.
195 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
196 {
197 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
198 {
199 // If a child of a mega-region, we shouldn't have any terrain allocated for us
200 ReleaseGroundPlaneAndTerrain();
201 // If doing the mega-prim stuff and we are the child of the zero region,
202 // the terrain is added to our parent
203 if (MegaRegionParentPhysicsScene is BSScene)
204 {
205 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
206 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
207 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
208 }
209 }
210 else
211 {
212 // If not doing the mega-prim thing, just change the terrain
213 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
214
215 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
216 }
217 });
218 }
219
220 // Another region is calling this region and passing a terrain.
221 // A region that is not the mega-region root will pass its terrain to the root region so the root region
222 // physics engine will have all the terrains.
223 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
224 {
225 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
226 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
227 {
228 UpdateTerrain(id, heightMap, minCoords, maxCoords);
229 });
230 }
231
232 // If called for terrain has has not been previously allocated, a new terrain will be built
233 // based on the passed information. The 'id' should be either the terrain id or
234 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
235 // The latter feature is for creating child terrains for mega-regions.
236 // If there is an existing terrain body, a new
237 // terrain shape is created and added to the body.
238 // This call is most often used to update the heightMap and parameters of the terrain.
239 // (The above does suggest that some simplification/refactoring is in order.)
240 // Called during taint-time.
241 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
242 {
243 // Find high and low points of passed heightmap.
244 // The min and max passed in is usually the area objects can be in (maximum
245 // object height, for instance). The terrain wants the bounding box for the
246 // terrain so replace passed min and max Z with the actual terrain min/max Z.
247 float minZ = float.MaxValue;
248 float maxZ = float.MinValue;
249 foreach (float height in heightMap)
250 {
251 if (height < minZ) minZ = height;
252 if (height > maxZ) maxZ = height;
253 }
254 if (minZ == maxZ)
255 {
256 // If min and max are the same, reduce min a little bit so a good bounding box is created.
257 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
258 }
259 minCoords.Z = minZ;
260 maxCoords.Z = maxZ;
261
262 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
263 BSScene.DetailLogZero, id, minCoords, maxCoords);
264
265 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
266
267 lock (m_terrains)
268 {
269 BSTerrainPhys terrainPhys;
270 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
271 {
272 // There is already a terrain in this spot. Free the old and build the new.
273 DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
274 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords);
275
276 // Remove old terrain from the collection
277 m_terrains.Remove(terrainRegionBase);
278 // Release any physical memory it may be using.
279 terrainPhys.Dispose();
280
281 if (MegaRegionParentPhysicsScene == null)
282 {
283 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
284 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
285 m_terrains.Add(terrainRegionBase, newTerrainPhys);
286
287 m_terrainModified = true;
288 }
289 else
290 {
291 // It's possible that Combine() was called after this code was queued.
292 // If we are a child of combined regions, we don't create any terrain for us.
293 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
294
295 // Get rid of any terrain that may have been allocated for us.
296 ReleaseGroundPlaneAndTerrain();
297
298 // I hate doing this, but just bail
299 return;
300 }
301 }
302 else
303 {
304 // We don't know about this terrain so either we are creating a new terrain or
305 // our mega-prim child is giving us a new terrain to add to the phys world
306
307 // if this is a child terrain, calculate a unique terrain id
308 uint newTerrainID = id;
309 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
310 newTerrainID = ++m_terrainCount;
311
312 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
313 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
314 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
315 m_terrains.Add(terrainRegionBase, newTerrainPhys);
316
317 m_terrainModified = true;
318 }
319 }
320 }
321
322 // TODO: redo terrain implementation selection to allow other base types than heightMap.
323 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
324 {
325 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
326 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
327 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
328 BSTerrainPhys newTerrainPhys = null;
329 switch ((int)BSParam.TerrainImplementation)
330 {
331 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
332 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
333 heightMap, minCoords, maxCoords);
334 break;
335 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
336 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
337 heightMap, minCoords, maxCoords);
338 break;
339 default:
340 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
341 LogHeader,
342 (int)BSParam.TerrainImplementation,
343 BSParam.TerrainImplementation,
344 m_physicsScene.RegionName, terrainRegionBase);
345 break;
346 }
347 return newTerrainPhys;
348 }
349
350 // Return 'true' of this position is somewhere in known physical terrain space
351 public bool IsWithinKnownTerrain(Vector3 pos)
352 {
353 Vector3 terrainBaseXYZ;
354 BSTerrainPhys physTerrain;
355 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
356 }
357
358 // Return a new position that is over known terrain if the position is outside our terrain.
359 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
360 {
361 float edgeEpsilon = 0.1f;
362
363 Vector3 ret = pPos;
364
365 // First, base addresses are never negative so correct for that possible problem.
366 if (ret.X < 0f || ret.Y < 0f)
367 {
368 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
369 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
370 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
371 BSScene.DetailLogZero, pPos, ret);
372 }
373
374 // Can't do this function if we don't know about any terrain.
375 if (m_terrains.Count == 0)
376 return ret;
377
378 int loopPrevention = 10;
379 Vector3 terrainBaseXYZ;
380 BSTerrainPhys physTerrain;
381 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
382 {
383 // The passed position is not within a known terrain area.
384 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
385
386 // Must be off the top of a region. Find an adjacent region to move into.
387 // The returned terrain is always 'lower'. That is, closer to <0,0>.
388 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
389
390 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
391 {
392 // moving down into a new region in the X dimension. New position will be the max in the new base.
393 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
394 }
395 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
396 {
397 // moving down into a new region in the X dimension. New position will be the max in the new base.
398 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
399 }
400 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
401 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
402
403 if (loopPrevention-- < 0f)
404 {
405 // The 'while' is a little dangerous so this prevents looping forever if the
406 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
407 // the list of terrains is in transition.
408 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
409 break;
410 }
411 }
412
413 return ret;
414 }
415
416 // Given an X and Y, find the height of the terrain.
417 // Since we could be handling multiple terrains for a mega-region,
418 // the base of the region is calcuated assuming all regions are
419 // the same size and that is the default.
420 // Once the heightMapInfo is found, we have all the information to
421 // compute the offset into the array.
422 private float lastHeightTX = 999999f;
423 private float lastHeightTY = 999999f;
424 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
425 public float GetTerrainHeightAtXYZ(Vector3 pos)
426 {
427 float tX = pos.X;
428 float tY = pos.Y;
429 // You'd be surprized at the number of times this routine is called
430 // with the same parameters as last time.
431 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
432 return lastHeight;
433 m_terrainModified = false;
434
435 lastHeightTX = tX;
436 lastHeightTY = tY;
437 float ret = HEIGHT_GETHEIGHT_RET;
438
439 Vector3 terrainBaseXYZ;
440 BSTerrainPhys physTerrain;
441 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
442 {
443 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
444 }
445 else
446 {
447 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
448 LogHeader, m_physicsScene.RegionName, tX, tY);
449 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
450 BSScene.DetailLogZero, pos, terrainBaseXYZ);
451 }
452
453 lastHeight = ret;
454 return ret;
455 }
456
457 public float GetWaterLevelAtXYZ(Vector3 pos)
458 {
459 float ret = WATER_HEIGHT_GETHEIGHT_RET;
460
461 Vector3 terrainBaseXYZ;
462 BSTerrainPhys physTerrain;
463 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
464 {
465 ret = physTerrain.GetWaterLevelAtXYZ(pos);
466 }
467 else
468 {
469 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
470 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
471 }
472 return ret;
473 }
474
475 // Given an address, return 'true' of there is a description of that terrain and output
476 // the descriptor class and the 'base' fo the addresses therein.
477 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
478 {
479 bool ret = false;
480
481 Vector3 terrainBaseXYZ = Vector3.Zero;
482 if (pos.X < 0f || pos.Y < 0f)
483 {
484 // We don't handle negative addresses so just make up a base that will not be found.
485 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
486 }
487 else
488 {
489 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
490 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
491 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
492 }
493
494 BSTerrainPhys physTerrain = null;
495 lock (m_terrains)
496 {
497 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
498 }
499 outTerrainBase = terrainBaseXYZ;
500 outPhysTerrain = physTerrain;
501 return ret;
502 }
503
504 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
505 // this one. Usually used to return an out of bounds object to a known place.
506 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
507 {
508 Vector3 ret = pTerrainBase;
509
510 // Can't do this function if we don't know about any terrain.
511 if (m_terrains.Count == 0)
512 return ret;
513
514 // Just some sanity
515 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
516 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
517 ret.Z = 0f;
518
519 lock (m_terrains)
520 {
521 // Once down to the <0,0> region, we have to be done.
522 while (ret.X > 0f || ret.Y > 0f)
523 {
524 if (ret.X > 0f)
525 {
526 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
527 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
528 if (m_terrains.ContainsKey(ret))
529 break;
530 }
531 if (ret.Y > 0f)
532 {
533 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
534 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
535 if (m_terrains.ContainsKey(ret))
536 break;
537 }
538 }
539 }
540
541 return ret;
542 }
543
544 // Although no one seems to check this, I do support combining.
545 public bool SupportsCombining()
546 {
547 return true;
548 }
549
550 // This routine is called two ways:
551 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
552 // extent of the combined regions. This is to inform the parent of the size
553 // of the combined regions.
554 // and one with 'offset' as the offset of the child region to the base region,
555 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
556 // child of its relative base and new parent.
557 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
558 {
559 m_worldOffset = offset;
560 m_worldMax = extents;
561 MegaRegionParentPhysicsScene = pScene;
562 if (pScene != null)
563 {
564 // We are a child.
565 // We want m_worldMax to be the highest coordinate of our piece of terrain.
566 m_worldMax = offset + DefaultRegionSize;
567 }
568 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
569 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
570 }
571
572 // Unhook all the combining that I know about.
573 public void UnCombine(PhysicsScene pScene)
574 {
575 // Just like ODE, we don't do anything yet.
576 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
577 }
578
579
580 private void DetailLog(string msg, params Object[] args)
581 {
582 m_physicsScene.PhysicsLogging.Write(msg, args);
583 }
584}
585}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
new file mode 100755
index 0000000..e4ca098
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
@@ -0,0 +1,441 @@
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.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class BSTerrainMesh : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
46
47 private float[] m_savedHeightMap;
48 int m_sizeX;
49 int m_sizeY;
50
51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody;
53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id)
56 {
57 }
58
59 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
60 : base(physicsScene, regionBase, id)
61 {
62 }
63
64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id)
68 {
69 int indicesCount;
70 int[] indices;
71 int verticesCount;
72 float[] vertices;
73
74 m_savedHeightMap = initialMap;
75
76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78
79 bool meshCreationSuccess = false;
80 if (BSParam.TerrainMeshMagnification == 1)
81 {
82 // If a magnification of one, use the old routine that is tried and true.
83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
84 initialMap, m_sizeX, m_sizeY, // input size
85 Vector3.Zero, // base for mesh
86 out indicesCount, out indices, out verticesCount, out vertices);
87 }
88 else
89 {
90 // Other magnifications use the newer routine
91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
92 initialMap, m_sizeX, m_sizeY, // input size
93 BSParam.TerrainMeshMagnification,
94 physicsScene.TerrainManager.DefaultRegionSize,
95 Vector3.Zero, // base for mesh
96 out indicesCount, out indices, out verticesCount, out vertices);
97 }
98 if (!meshCreationSuccess)
99 {
100 // DISASTER!!
101 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
102 m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
103 // Something is very messed up and a crash is in our future.
104 return;
105 }
106
107 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
109
110 m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
111 if (!m_terrainShape.HasPhysicalShape)
112 {
113 // DISASTER!!
114 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
115 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
116 // Something is very messed up and a crash is in our future.
117 return;
118 }
119
120 Vector3 pos = regionBase;
121 Quaternion rot = Quaternion.Identity;
122
123 m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
124 if (!m_terrainBody.HasPhysicalBody)
125 {
126 // DISASTER!!
127 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
128 // Something is very messed up and a crash is in our future.
129 return;
130 }
131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
132
133 // Set current terrain attributes
134 m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
135 m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
136 m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
137 m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
138 m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
139
140 // Static objects are not very massive.
141 m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
142
143 // Put the new terrain to the world of physical objects
144 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
145
146 // Redo its bounding box now that it is in the world
147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
148
149 m_terrainBody.collisionType = CollisionType.Terrain;
150 m_terrainBody.ApplyCollisionMask(m_physicsScene);
151
152 if (BSParam.UseSingleSidedMeshes)
153 {
154 m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
155 m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
156 }
157
158 // Make it so the terrain will not move or be considered for movement.
159 m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
160 }
161
162 public override void Dispose()
163 {
164 if (m_terrainBody.HasPhysicalBody)
165 {
166 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
167 // Frees both the body and the shape.
168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
169 m_terrainBody.Clear();
170 m_terrainShape.Clear();
171 }
172 }
173
174 public override float GetTerrainHeightAtXYZ(Vector3 pos)
175 {
176 // For the moment use the saved heightmap to get the terrain height.
177 // TODO: raycast downward to find the true terrain below the position.
178 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
179
180 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
181 try
182 {
183 ret = m_savedHeightMap[mapIndex];
184 }
185 catch
186 {
187 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
188 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
189 LogHeader, TerrainBase, pos);
190 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
191 }
192 return ret;
193 }
194
195 // The passed position is relative to the base of the region.
196 public override float GetWaterLevelAtXYZ(Vector3 pos)
197 {
198 return m_physicsScene.SimpleWaterLevel;
199 }
200
201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
202 // Return 'true' if successfully created.
203 public static bool ConvertHeightmapToMesh( BSScene physicsScene,
204 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
205 Vector3 extentBase, // base to be added to all vertices
206 out int indicesCountO, out int[] indicesO,
207 out int verticesCountO, out float[] verticesO)
208 {
209 bool ret = false;
210
211 int indicesCount = 0;
212 int verticesCount = 0;
213 int[] indices = new int[0];
214 float[] vertices = new float[0];
215
216 // Simple mesh creation which assumes magnification == 1.
217 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
218
219 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
220 // from zero to <= sizeX). The triangle indices are then generated as two triangles
221 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
222 // column of vertices are used to complete the triangles of the last row and column
223 // of the heightmap.
224 try
225 {
226 // One vertice per heightmap value plus the vertices off the side and bottom edge.
227 int totalVertices = (sizeX + 1) * (sizeY + 1);
228 vertices = new float[totalVertices * 3];
229 int totalIndices = sizeX * sizeY * 6;
230 indices = new int[totalIndices];
231
232 if (physicsScene != null)
233 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
234 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
235 float minHeight = float.MaxValue;
236 // Note that sizeX+1 vertices are created since there is land between this and the next region.
237 for (int yy = 0; yy <= sizeY; yy++)
238 {
239 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
240 {
241 int offset = yy * sizeX + xx;
242 // Extend the height with the height from the last row or column
243 if (yy == sizeY) offset -= sizeX;
244 if (xx == sizeX) offset -= 1;
245 float height = heightMap[offset];
246 minHeight = Math.Min(minHeight, height);
247 vertices[verticesCount + 0] = (float)xx + extentBase.X;
248 vertices[verticesCount + 1] = (float)yy + extentBase.Y;
249 vertices[verticesCount + 2] = height + extentBase.Z;
250 verticesCount += 3;
251 }
252 }
253 verticesCount = verticesCount / 3;
254
255 for (int yy = 0; yy < sizeY; yy++)
256 {
257 for (int xx = 0; xx < sizeX; xx++)
258 {
259 int offset = yy * (sizeX + 1) + xx;
260 // Each vertices is presumed to be the upper left corner of a box of two triangles
261 indices[indicesCount + 0] = offset;
262 indices[indicesCount + 1] = offset + 1;
263 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
264 indices[indicesCount + 3] = offset + 1;
265 indices[indicesCount + 4] = offset + sizeX + 2;
266 indices[indicesCount + 5] = offset + sizeX + 1;
267 indicesCount += 6;
268 }
269 }
270
271 ret = true;
272 }
273 catch (Exception e)
274 {
275 if (physicsScene != null)
276 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
277 LogHeader, physicsScene.RegionName, extentBase, e);
278 }
279
280 indicesCountO = indicesCount;
281 indicesO = indices;
282 verticesCountO = verticesCount;
283 verticesO = vertices;
284
285 return ret;
286 }
287
288 private class HeightMapGetter
289 {
290 private float[] m_heightMap;
291 private int m_sizeX;
292 private int m_sizeY;
293 public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
294 {
295 m_heightMap = pHeightMap;
296 m_sizeX = pSizeX;
297 m_sizeY = pSizeY;
298 }
299 // The heightmap is extended as an infinite plane at the last height
300 public float GetHeight(int xx, int yy)
301 {
302 int offset = 0;
303 // Extend the height with the height from the last row or column
304 if (yy >= m_sizeY)
305 if (xx >= m_sizeX)
306 offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
307 else
308 offset = (m_sizeY - 1) * m_sizeX + xx;
309 else
310 if (xx >= m_sizeX)
311 offset = yy * m_sizeX + (m_sizeX - 1);
312 else
313 offset = yy * m_sizeX + xx;
314
315 return m_heightMap[offset];
316 }
317 }
318
319 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
320 // Version that handles magnification.
321 // Return 'true' if successfully created.
322 public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
323 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
324 int magnification, // number of vertices per heighmap step
325 Vector3 extent, // dimensions of the output mesh
326 Vector3 extentBase, // base to be added to all vertices
327 out int indicesCountO, out int[] indicesO,
328 out int verticesCountO, out float[] verticesO)
329 {
330 bool ret = false;
331
332 int indicesCount = 0;
333 int verticesCount = 0;
334 int[] indices = new int[0];
335 float[] vertices = new float[0];
336
337 HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
338
339 // The vertices dimension of the output mesh
340 int meshX = sizeX * magnification;
341 int meshY = sizeY * magnification;
342 // The output size of one mesh step
343 float meshXStep = extent.X / meshX;
344 float meshYStep = extent.Y / meshY;
345
346 // Create an array of vertices that is meshX+1 by meshY+1 (note the loop
347 // from zero to <= meshX). The triangle indices are then generated as two triangles
348 // per heightmap point. There are meshX by meshY of these squares. The extra row and
349 // column of vertices are used to complete the triangles of the last row and column
350 // of the heightmap.
351 try
352 {
353 // Vertices for the output heightmap plus one on the side and bottom to complete triangles
354 int totalVertices = (meshX + 1) * (meshY + 1);
355 vertices = new float[totalVertices * 3];
356 int totalIndices = meshX * meshY * 6;
357 indices = new int[totalIndices];
358
359 if (physicsScene != null)
360 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
361 BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
362 totalVertices, totalIndices, extentBase);
363
364 float minHeight = float.MaxValue;
365 // Note that sizeX+1 vertices are created since there is land between this and the next region.
366 // Loop through the output vertices and compute the mediun height in between the input vertices
367 for (int yy = 0; yy <= meshY; yy++)
368 {
369 for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
370 {
371 float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
372 int stepY = (int)offsetY;
373 float fractionalY = offsetY - (float)stepY;
374 float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
375 int stepX = (int)offsetX;
376 float fractionalX = offsetX - (float)stepX;
377
378 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
379 // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
380
381 // get the four corners of the heightmap square the mesh point is in
382 float heightUL = hmap.GetHeight(stepX , stepY );
383 float heightUR = hmap.GetHeight(stepX + 1, stepY );
384 float heightLL = hmap.GetHeight(stepX , stepY + 1);
385 float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
386
387 // bilinear interplolation
388 float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
389 + heightUR * fractionalX * (1 - fractionalY)
390 + heightLL * (1 - fractionalX) * fractionalY
391 + heightLR * fractionalX * fractionalY;
392
393 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
394 // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
395
396 minHeight = Math.Min(minHeight, height);
397
398 vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
399 vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
400 vertices[verticesCount + 2] = height + extentBase.Z;
401 verticesCount += 3;
402 }
403 }
404 // The number of vertices generated
405 verticesCount /= 3;
406
407 // Loop through all the heightmap squares and create indices for the two triangles for that square
408 for (int yy = 0; yy < meshY; yy++)
409 {
410 for (int xx = 0; xx < meshX; xx++)
411 {
412 int offset = yy * (meshX + 1) + xx;
413 // Each vertices is presumed to be the upper left corner of a box of two triangles
414 indices[indicesCount + 0] = offset;
415 indices[indicesCount + 1] = offset + 1;
416 indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
417 indices[indicesCount + 3] = offset + 1;
418 indices[indicesCount + 4] = offset + meshX + 2;
419 indices[indicesCount + 5] = offset + meshX + 1;
420 indicesCount += 6;
421 }
422 }
423
424 ret = true;
425 }
426 catch (Exception e)
427 {
428 if (physicsScene != null)
429 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
430 LogHeader, physicsScene.RegionName, extentBase, e);
431 }
432
433 indicesCountO = indicesCount;
434 indicesO = indices;
435 verticesCountO = verticesCount;
436 verticesO = vertices;
437
438 return ret;
439 }
440}
441}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
new file mode 100755
index 0000000..5932461
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
@@ -0,0 +1,277 @@
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 shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public BSPhysicsShapeType shapeType;
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(shapeType.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, float pSizeX, float pSizeY) {
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 = pSizeX;
176 sizeY = pSizeY;
177 }
178 public uint ID;
179 public float[] heightMap;
180 public OMV.Vector3 terrainRegionBase;
181 public OMV.Vector3 minCoords;
182 public OMV.Vector3 maxCoords;
183 public float sizeX, sizeY;
184 public float minZ, maxZ;
185 public BulletShape terrainShape;
186 public BulletBody terrainBody;
187}
188
189// The general class of collsion object.
190public enum CollisionType
191{
192 Avatar,
193 PhantomToOthersAvatar, // An avatar that it phantom to other avatars but not to anything else
194 Groundplane,
195 Terrain,
196 Static,
197 Dynamic,
198 VolumeDetect,
199 // Linkset, // A linkset should be either Static or Dynamic
200 LinksetChild,
201 Unknown
202};
203
204// Hold specification of group and mask collision flags for a CollisionType
205public struct CollisionTypeFilterGroup
206{
207 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
208 {
209 type = t;
210 group = g;
211 mask = m;
212 }
213 public CollisionType type;
214 public uint group;
215 public uint mask;
216};
217
218public static class BulletSimData
219{
220
221// Map of collisionTypes to flags for collision groups and masks.
222// An object's 'group' is the collison groups this object belongs to
223// An object's 'filter' is the groups another object has to belong to in order to collide with me
224// A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0)
225//
226// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
227// but, instead, use references to this dictionary. Finding and debugging
228// collision flag problems will be made easier.
229public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
230 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
231{
232 { CollisionType.Avatar,
233 new CollisionTypeFilterGroup(CollisionType.Avatar,
234 (uint)CollisionFilterGroups.BCharacterGroup,
235 (uint)(CollisionFilterGroups.BAllGroup))
236 },
237 { CollisionType.PhantomToOthersAvatar,
238 new CollisionTypeFilterGroup(CollisionType.PhantomToOthersAvatar,
239 (uint)CollisionFilterGroups.BCharacterGroup,
240 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup))
241 },
242 { CollisionType.Groundplane,
243 new CollisionTypeFilterGroup(CollisionType.Groundplane,
244 (uint)CollisionFilterGroups.BGroundPlaneGroup,
245 // (uint)CollisionFilterGroups.BAllGroup)
246 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
247 },
248 { CollisionType.Terrain,
249 new CollisionTypeFilterGroup(CollisionType.Terrain,
250 (uint)CollisionFilterGroups.BTerrainGroup,
251 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
252 },
253 { CollisionType.Static,
254 new CollisionTypeFilterGroup(CollisionType.Static,
255 (uint)CollisionFilterGroups.BStaticGroup,
256 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
257 },
258 { CollisionType.Dynamic,
259 new CollisionTypeFilterGroup(CollisionType.Dynamic,
260 (uint)CollisionFilterGroups.BSolidGroup,
261 (uint)(CollisionFilterGroups.BAllGroup))
262 },
263 { CollisionType.VolumeDetect,
264 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
265 (uint)CollisionFilterGroups.BSensorTrigger,
266 (uint)(~CollisionFilterGroups.BSensorTrigger))
267 },
268 { CollisionType.LinksetChild,
269 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
270 (uint)CollisionFilterGroups.BLinksetChildGroup,
271 (uint)(CollisionFilterGroups.BNoneGroup))
272 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
273 },
274};
275
276}
277}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
new file mode 100755
index 0000000..0453376
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
@@ -0,0 +1,379 @@
1CURRENT PROBLEMS TO FIX AND/OR LOOK AT
2=================================================
3Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass.
4 Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive?
5 Negative buoyancy computed correctly
6Center-of-gravity
7Computation of mesh mass. How done? How should it be done?
8Enable vehicle border crossings (at least as poorly as ODE)
9 Terrain skirts
10 Avatar created in previous region and not new region when crossing border
11 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
12User settable terrain mesh
13 Allow specifying as convex or concave and use different getHeight functions depending
14Boats, when turning nose down into the water
15 Acts like rotation around Z is also effecting rotation around X and Y
16Deleting a linkset while standing on the root will leave the physical shape of the root behind.
17 Not sure if it is because standing on it. Done with large prim linksets.
18Linkset child rotations.
19 Nebadon spiral tube has middle sections which are rotated wrong.
20 Select linked spiral tube. Delink and note where the middle section ends up.
21Teravus llMoveToTarget script debug
22 Mixing of hover, buoyancy/gravity, moveToTarget, into one force
23 Setting hover height to zero disables hover even if hover flags are on (from SL wiki)
24limitMotorUp calibration (more down?)
25llRotLookAt
26llLookAt
27Convert to avatar mesh capsule. Include rotation of capsule.
28Vehicle script tuning/debugging
29 Avanti speed script
30 Weapon shooter script
31Move material definitions (friction, ...) into simulator.
32osGetPhysicsEngineVerion() and create a version code for the C++ DLL
33One sided meshes? Should terrain be built into a closed shape?
34 When meshes get partially wedged into the terrain, they cannot push themselves out.
35 It is possible that Bullet processes collisions whether entering or leaving a mesh.
36 Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869
37Small physical objects do not interact correctly
38 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
39 The chain will fall apart and pairs will dance around on ground
40 Chains of 1x1x.2 will stay connected but will dance.
41 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
42
43VEHICLES TODO LIST:
44=================================================
45LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
46 What are the limits in SL?
47 Same for other velocity settings.
48UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
49 https://github.com/UbitUmarov/Ubit-opensim
50Some vehicles should not be able to turn if no speed or off ground.
51Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
52Neb car jiggling left and right
53 Happens on terrain and any other mesh object. Flat cubes are much smoother.
54 This has been reduced but not eliminated.
55Implement referenceFrame for all the motion routines.
56Verify llGetVel() is returning a smooth and good value for vehicle movement.
57llGetVel() should return the root's velocity if requested in a child prim.
58Implement function efficiency for lineaar and angular motion.
59Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
60Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
61 A kludge that isn't fixing the real problem of Bullet adding extra motion.
62Incorporate inter-relationship of angular corrections. For instance, angularDeflection
63 and angularMotorUp will compute same X or Y correction. When added together
64 creates over-correction and over-shoot and wabbling.
65Vehicle attributes are not restored when a vehicle is rezzed on region creation
66 Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized.
67What to do if vehicle and prim buoyancy differ?
68
69GENERAL TODO LIST:
70=================================================
71Resitution of a prim works on another prim but not on terrain.
72 The dropped prim doesn't bounce properly on the terrain.
73Add a sanity check for PIDTarget location.
74Level-of-detail for mesh creation. Prims with circular interiors require lod of 32.
75 Is much saved with lower LODs? At the moment, all set to 32.
76Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't.
77 If arrow show at prim, collision reported about 1/3 of time. If collision reported,
78 both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times.
79 Shooting 5m sphere "arrows" at 60m/s.
80llMoveToTarget objects are not effected by gravity until target is removed.
81Compute CCD parameters based on body size
82Can solver iterations be changed per body/shape? Can be for constraints but what
83 about regular vehicles?
84Implement llSetPhysicalMaterial.
85 extend it with Center-of-mass, rolling friction, density
86Implement llSetForceAndTorque.
87Change BSPrim.moveToTarget to used forces rather than changing position
88 Changing position allows one to move through walls
89Implement an avatar mesh shape. The Bullet capsule is way too limited.
90 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
91Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
92Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
93Duplicating a physical prim causes old prim to jump away
94 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
95Scenes with hundred of thousands of static objects take a lot of physics CPU time.
96Gun sending shooter flying.
97Collision margin (gap between physical objects lying on each other)
98Boundry checking (crashes related to crossing boundry)
99 Add check for border edge position for avatars and objects.
100 Verify the events are created for border crossings.
101Implement ShapeCollection.Dispose()
102Implement water as a plain or mesh so raycasting and collisions can happen with same.
103Add collision penetration return
104 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
105Linkset.Position and Linkset.Orientation requre rewrite to properly return
106 child position. LinksetConstraint acts like it's at taint time!!
107Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
108Should the different PID factors have non-equal contributions for different
109 values of Efficiency?
110Selecting and deselecting physical objects causes CPU processing time to jump
111 http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1
112 put thousand physical objects, select and deselect same. CPU time will be large.
113Re-implement buoyancy as a separate force on the object rather than diddling gravity.
114 Register a pre-step event to add the force.
115More efficient memory usage when passing hull information from BSPrim to BulletSim
116Physical and phantom will drop through the terrain
117
118
119LINKSETS
120======================================================
121Child prims do not report collisions
122Allow children of a linkset to be phantom:
123 http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html
124 Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast.
125Editing a child of a linkset causes the child to go phantom
126 Move a child prim once when it is physical and can never move it again without it going phantom
127Offset the center of the linkset to be the geometric center of all the prims
128 Not quite the same as the center-of-gravity
129Linksets should allow collisions to individual children
130 Add LocalID to children shapes in LinksetCompound and create events for individuals
131LinksetCompound: when one of the children changes orientation (like tires
132 turning on a vehicle, the whole compound object is rebuilt. Optimize this
133 so orientation/position of individual children can change without a rebuild.
134Verify/think through scripts in children of linksets. What do they reference
135 and return when getting position, velocity, ...
136Confirm constraint linksets still work after making all the changes for compound linksets.
137Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding
138Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
139 For compound linksets, add ability to remove or reposition individual child shapes.
140Speed up creation of large physical linksets
141 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
142 REALLY bad for very large physical linksets (freezes the sim for many seconds).
143Eliminate collisions between objects in a linkset. (LinksetConstraint)
144 Have UserPointer point to struct with localID and linksetID?
145 Objects in original linkset still collide with each other?
146
147MORE
148======================================================
149Compute avatar size and scale correctly. Now it is a bit off from the capsule size.
150Create tests for different interface components
151 Have test objects/scripts measure themselves and turn color if correct/bad
152 Test functions in SL and calibrate correctness there
153 Create auto rezzer and tracker to run through the tests
154Do we need to do convex hulls all the time? Can complex meshes be left meshes?
155 There is some problem with meshes and collisions
156 Hulls are not as detailed as meshes. Hulled vehicles insides are different shape.
157Debounce avatar contact so legs don't keep folding up when standing.
158Add border extensions to terrain to help region crossings and objects leaving region.
159Use a different capsule shape for avatar when sitting
160 LL uses a pyrimidal shape scaled by the avatar's bounding box
161 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
162Performance test with lots of avatars. Can BulletSim support a thousand?
163Optimize collisions in C++: only send up to the object subscribed to collisions.
164 Use collision subscription and remove the collsion(A,B) and collision(B,A)
165Check whether SimMotionState needs large if statement (see TODO).
166Implement 'top colliders' info.
167Avatar jump
168Performance measurement and changes to make quicker.
169Implement detailed physics stats (GetStats()).
170Measure performance improvement from hulls
171Test not using ghost objects for volume detect implementation.
172Performance of closures and delegates for taint processing
173 Are there faster ways?
174 Is any slowdown introduced by the existing implementation significant?
175Is there are more efficient method of implementing pre and post step actions?
176 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
177Physics Arena central pyramid: why is one side permiable?
178In SL, perfect spheres don't seem to have rolling friction. Add special case.
179Enforce physical parameter min/max:
180 Gravity: [-1, 28]
181 Friction: [0, 255]
182 Density: [1, 22587]
183 Restitution [0, 1]
184 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
185Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
186Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html
187
188INTERNAL IMPROVEMENT/CLEANUP
189=================================================
190Create the physical wrapper classes (BulletBody, BulletShape) by methods on
191 BSAPITemplate and make their actual implementation Bullet engine specific.
192 For the short term, just call the existing functions in ShapeCollection.
193Consider moving prim/character body and shape destruction in destroy()
194 to postTimeTime rather than protecting all the potential sets that
195 might have been queued up.
196Remove unused fields from ShapeData (not used in API2)
197Remove unused fields from pinned memory shared parameter block
198 Create parameter variables in BSScene to replace same.
199Breakout code for mesh/hull/compound/native into separate BSShape* classes
200 Standardize access to building and reference code.
201 The skeleton classes are in the sources but are not complete or linked in.
202Make BSBody and BSShape real classes to centralize creation/changin/destruction
203 Convert state and parameter calls from BulletSimAPI direct calls to
204 calls on BSBody and BSShape
205Generalize Dynamics and PID with standardized motors.
206Generalize Linkset and vehicles into PropertyManagers
207 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
208 Potentially add events for shape destruction, etc.
209Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
210 BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc.
211Implement linkset by setting position of children when root updated. (LinksetManual)
212 Linkset implementation using manual prim movement.
213LinkablePrim class? Would that simplify/centralize the linkset logic?
214BSScene.UpdateParameterSet() is broken. How to set params on objects?
215Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
216 bob at the water level. BSPrim.PositionSanityCheck()
217Should taints check for existance or activeness of target?
218 When destroying linksets/etc, taints can be generated for objects that are
219 actually gone when the taint happens. Crashes don't happen because the taint closure
220 keeps the object from being freed, but that is just an accident.
221 Possibly have an 'active' flag that is checked by the taint processor?
222Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
223Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
224There are TOO MANY interfaces from BulletSim core to Bullet itself
225 Think of something to eliminate one or more of the layers
226
227THREADING
228=================================================
229Do taint action immediately if not actually executing Bullet.
230 Add lock around Bullet execution and just do taint actions if simulation is not happening.
231
232DONE DONE DONE DONE
233=================================================
234Cleanup code in BSDynamics by using motors. (Resolution: started)
235Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
236 Would have better and adjustable resolution.
237Build terrain mesh so heighmap is height of the center of the square meter.
238 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
239Terrain as mesh. (Resolution: done)
240How are static linksets seen by the physics engine?
241 Resolution: they are not linked in physics. When moved, all the children are repositioned.
242Convert BSCharacter to use all API2 (Resolution: done)
243Avatar pushing difficult (too heavy?)
244Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
245Remove old code in DLL (all non-API2 stuff). (Resolution: done)
246Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
247Debug Bullet internal stats output (why is timing all wrong?)
248 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
249Implement meshes or just verify that they work. (Resolution: they do!)
250Do prim hash codes work for sculpties and meshes? (Resolution: yes)
251Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
252 Compound shapes will need the LocalID in the shapes and collision
253 processing to get it from there.
254Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
255Package Bullet source mods for Bullet internal stats output
256 (Resolution: move code into WorldData.h rather than relying on patches)
257Single prim vehicles don't seem to properly vehiclize.
258 (Resolution: mass was not getting set properly for single prim linksets)
259Add material type linkage and input all the material property definitions.
260 Skeleton classes and table are in the sources but are not filled or used.
261 (Resolution:
262Neb vehicle taking > 25ms of physics time!!
263 (Resolution: compound linksets were being rebuild WAY too often)
264Avatar height off after unsitting (floats off ground)
265 Editting appearance then moving restores.
266 Must not be initializing height when recreating capsule after unsit.
267 (Resolution: confusion of scale vs size for native objects removed)
268Light cycle falling over when driving (Resolution: implemented angularMotorUp)
269Should vehicle angular/linear movement friction happen after all the components
270 or does it only apply to the basic movement?
271 (Resolution: friction added before returning newly computed motor value.
272 What is expected by some vehicles (turning up friction to moderate speed))
273Tune terrain/object friction to be closer to SL.
274 (Resolution: added material type with friction and resolution)
275Smooth avatar movement with motor (DONE)
276 Should motor update be all at taint-time? (Yes, DONE)
277 Fix avatar slowly sliding when standing (zero motion when stopped) (DONE)
278 (Resolution: added BSVMotor for avatar starting and stopping)
279llApplyImpulse()
280 Compare mass/movement in OS and SL. Calibrate actions. (DONE)
281 (Resolution: tested on SL and OS. AddForce scales the force for timestep)
282llSetBuoyancy() (DONE)
283 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
284Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
285 (Resolution: set default density to 3.5 (from 60) which is closer to SL)
286Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
287 (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
288Meshes rendering as bounding boxes (DONE)
289 (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
290llMoveToTarget (Resolution: added simple motor to update the position.)
291Angular motor direction is global coordinates rather than local coordinates (DONE)
292Add vehicle collisions so IsColliding is properly reported. (DONE)
293 Needed for banking, limitMotorUp, movementLimiting, ...
294 (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it)
295VehicleAddForce is not scaled by the simulation step but it is only
296 applied for one step. Should it be scaled? (DONE)
297 (Resolution: use force for timed things, Impulse for immediate, non-timed things)
298Complete implemention of preStepActions (DONE)
299 Replace vehicle step call with prestep event.
300 Is there a need for postStepActions? postStepTaints?
301Disable activity of passive linkset children. (DONE)
302 Since the linkset is a compound object, the old prims are left lying
303 around and need to be phantomized so they don't collide, ...
304Remove HeightmapInfo from terrain specification (DONE)
305 Since C++ code does not need terrain height, this structure et al are not needed.
306Surfboard go wonky when turning (DONE)
307 Angular motor direction is global coordinates rather than local coordinates?
308 (Resolution: made angular motor direction correct coordinate system)
309Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE)
310 Msg Kayaker on OSGrid when working
311 (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the
312 same in SL as in OS/BulletSim)
313Boats float low in the water (DONE)
314Boats floating at proper level (DONE)
315When is force introduced by SetForce removed? The prestep action could go forever. (DONE)
316 (Resolution: setForce registers a prestep action which keeps applying the force)
317Child movement in linkset (don't rebuild linkset) (DONE 20130122))
318Avatar standing on a moving object should start to move with the object. (DONE 20130125)
319Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
320 Verify that angular motion specified around Z moves in the vehicle coordinates.
321 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
322Nebadon vehicles turning funny in arena (DONE)
323Lock axis (DONE 20130401)
324Terrain detail: double terrain mesh detail (DONE)
325Use the HACD convex hull routine in Bullet rather than the C# version.
326 Speed up hullifying large meshes. (DONE)
327Vehicle ride, get up, ride again. Second time vehicle does not act correctly.
328 Have to rez new vehicle and delete the old to fix situation.
329 (DONE 20130520: normalize rotations)
330Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd
331 position state where it will not settle onto ground properly, etc
332 (DONE 20130520: normalize rotations)
333Two of Nebadon vehicles in a sim max the CPU. This is new.
334 (DONE 20130520: two problems: if asset failed to mesh, constantly refetched
335 asset; vehicle was sending too many messages to all linkset members)
336Add material densities to the material types. (WILL NOT BE DONE: not how it is done)
337Avatars walking up stairs (DONE)
338Avatar movement
339 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
340 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE)
341 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
342After getting off a vehicle, the root prim is phantom (can be walked through)
343 Need to force a position update for the root prim after compound shape destruction
344 (DONE)
345Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
346 Regular triangle meshes don't do physical collisions.
347 (DONE: discovered GImpact is VERY CPU intensive)
348Script changing rotation of child prim while vehicle moving (eg turning wheel) causes
349 the wheel to appear to jump back. Looks like sending position from previous update.
350 (DONE: redo of compound linksets fixed problem)
351Refarb compound linkset creation to create a pseudo-root for center-of-mass
352 Let children change their shape to physical indendently and just add shapes to compound
353 (DONE: redo of compound linkset fixed problem)
354Vehicle angular vertical attraction (DONE: vegaslon code)
355vehicle angular banking (DONE: vegaslon code)
356Vehicle angular deflection (DONE: vegaslon code)
357 Preferred orientation angular correction fix
358Vehicles (Move smoothly)
359For limitMotorUp, use raycast down to find if vehicle is in the air.
360 (WILL NOT BE DONE: gravity does the job well enough)
361BSPrim.Force should set a continious force on the prim. The force should be
362 applied each tick. Some limits?
363 (DONE: added physical actors. Implemented SetForce, SetTorque, ...)
364Implement LSL physics controls. Like STATUS_ROTATE_X. (DONE)
365Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
366Avatar rotation (check out changes to ScenePresence for physical rotation) (DONE)
367Avatar running (what does phys engine need to do?) (DONE: multiplies run factor by walking force)
368setForce should set a constant force. Different than AddImpulse. (DONE)
369Add PID motor for avatar movement (slow to stop, ...) (WNBD: current works ok)
370Avatar movement motor check for zero or small movement. Somehow suppress small movements
371 when avatar has stopped and is just standing. Simple test for near zero has
372 the problem of preventing starting up (increase from zero) especially when falling.
373 (DONE: avatar movement actor knows if standing on stationary object and zeros motion)
374Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
375 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
376 (DONE)
377
378
379
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4f90eee
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.8.2.*")]
33
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs
new file mode 100755
index 0000000..48e74eb
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs
@@ -0,0 +1,156 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.Physics.BulletSPlugin;
38using OpenSim.Region.Physics.Manager;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin.Tests
44{
45[TestFixture]
46public class BasicVehicles : OpenSimTestCase
47{
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene PhysicsScene { get; set; }
52 BSPrim TestVehicle { get; set; }
53 Vector3 TestVehicleInitPosition { get; set; }
54 float simulationTimeStep = 0.089f;
55
56 [TestFixtureSetUp]
57 public void Init()
58 {
59 Dictionary<string, string> engineParams = new Dictionary<string, string>();
60 engineParams.Add("VehicleEnableAngularVerticalAttraction", "true");
61 engineParams.Add("VehicleAngularVerticalAttractionAlgorithm", "1");
62 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
63
64 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
65 Vector3 pos = new Vector3(100.0f, 100.0f, 0f);
66 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f;
67 TestVehicleInitPosition = pos;
68 Vector3 size = new Vector3(1f, 1f, 1f);
69 pbs.Scale = size;
70 Quaternion rot = Quaternion.Identity;
71 bool isPhys = false;
72 uint localID = 123;
73
74 PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID);
75 TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID];
76 // The actual prim shape creation happens at taint time
77 PhysicsScene.ProcessTaints();
78
79 }
80
81 [TestFixtureTearDown]
82 public void TearDown()
83 {
84 if (PhysicsScene != null)
85 {
86 // The Dispose() will also free any physical objects in the scene
87 PhysicsScene.Dispose();
88 PhysicsScene = null;
89 }
90 }
91
92 [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)]
93 [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)]
94 [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)]
95 [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)]
96 // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */]
97 // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */]
98 // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */]
99 // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */]
100 // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */]
101 // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */]
102 // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */]
103 // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */]
104 public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw)
105 {
106 // Enough simulation steps to cover the timescale the operation should take
107 int simSteps = (int)(timeScale / simulationTimeStep) + 1;
108
109 // Tip the vehicle
110 Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw);
111 TestVehicle.Orientation = initOrientation;
112
113 TestVehicle.Position = TestVehicleInitPosition;
114
115 // The vehicle controller is not enabled directly (by setting a vehicle type).
116 // Instead the appropriate values are set and calls are made just the parts of the
117 // controller we want to exercise. Stepping the physics engine then applies
118 // the actions of that one feature.
119 BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */);
120 if (vehicleActor != null)
121 {
122 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
123 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale);
124 // vehicleActor.enableAngularVerticalAttraction = true;
125
126 TestVehicle.IsPhysical = true;
127 PhysicsScene.ProcessTaints();
128
129 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up
130 for (int ii = 0; ii < simSteps; ii++)
131 {
132 vehicleActor.ForgetKnownVehicleProperties();
133 vehicleActor.ComputeAngularVerticalAttraction();
134 vehicleActor.PushKnownChanged();
135
136 PhysicsScene.Simulate(simulationTimeStep);
137 }
138 }
139
140 TestVehicle.IsPhysical = false;
141 PhysicsScene.ProcessTaints();
142
143 // After these steps, the vehicle should be upright
144 /*
145 float finalRoll, finalPitch, finalYaw;
146 TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw);
147 Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f));
148 Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f));
149 Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f));
150 */
151
152 Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation;
153 Assert.That(upPointer.Z, Is.GreaterThan(0.99f));
154 }
155}
156} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs
new file mode 100755
index 0000000..35cbc1d
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs
@@ -0,0 +1,56 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Tests.Common;
37
38namespace OpenSim.Region.Physics.BulletSPlugin.Tests
39{
40[TestFixture]
41public class BulletSimTests : OpenSimTestCase
42{
43 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
44 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
45
46 [TestFixtureSetUp]
47 public void Init()
48 {
49 }
50
51 [TestFixtureTearDown]
52 public void TearDown()
53 {
54 }
55}
56}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs
new file mode 100755
index 0000000..775bca2
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs
@@ -0,0 +1,100 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Collections.Generic;
31using System.Text;
32
33using Nini.Config;
34
35using OpenSim.Framework;
36using OpenSim.Region.Physics.Manager;
37using OpenSim.Region.Physics.Meshing;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin.Tests
42{
43// Utility functions for building up and tearing down the sample physics environments
44public static class BulletSimTestsUtil
45{
46 // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA"
47 // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults)
48 // May be 'null' if there are no overrides.
49 public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides)
50 {
51 IConfigSource openSimINI = new IniConfigSource();
52 IConfig startupConfig = openSimINI.AddConfig("Startup");
53 startupConfig.Set("physics", "BulletSim");
54 startupConfig.Set("meshing", "Meshmerizer");
55 startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps
56
57 IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim");
58 // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged".
59 // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged");
60 // bulletSimConfig.Set("BulletEngine", "BulletXNA");
61 bulletSimConfig.Set("MeshSculptedPrim", "false");
62 bulletSimConfig.Set("ForceSimplePrimMeshing", "true");
63 if (paramOverrides != null)
64 {
65 foreach (KeyValuePair<string, string> kvp in paramOverrides)
66 {
67 bulletSimConfig.Set(kvp.Key, kvp.Value);
68 }
69 }
70
71 // If a special directory exists, put detailed logging therein.
72 // This allows local testing/debugging without having to worry that the build engine will output logs.
73 if (Directory.Exists("physlogs"))
74 {
75 bulletSimConfig.Set("PhysicsLoggingDir","./physlogs");
76 bulletSimConfig.Set("PhysicsLoggingEnabled","True");
77 bulletSimConfig.Set("PhysicsLoggingDoFlush","True");
78 bulletSimConfig.Set("VehicleLoggingEnabled","True");
79 }
80
81 PhysicsPluginManager physicsPluginManager;
82 physicsPluginManager = new PhysicsPluginManager();
83 physicsPluginManager.LoadPluginsFromAssemblies("Physics");
84
85 Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
86
87 PhysicsScene pScene = physicsPluginManager.GetPhysicsScene(
88 "BulletSim", "Meshmerizer", openSimINI, "BSTestRegion", regionExtent);
89
90 BSScene bsScene = pScene as BSScene;
91
92 // Since the asset requestor is not initialized, any mesh or sculptie will be a cube.
93 // In the future, add a fake asset fetcher to get meshes and sculpts.
94 // bsScene.RequestAssetMethod = ???;
95
96 return bsScene;
97 }
98
99}
100}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs
new file mode 100644
index 0000000..5a5de11
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs
@@ -0,0 +1,205 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.Physics.BulletSPlugin;
38using OpenSim.Region.Physics.Manager;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin.Tests
44{
45[TestFixture]
46public class HullCreation : OpenSimTestCase
47{
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene PhysicsScene { get; set; }
52 Vector3 ObjectInitPosition;
53
54 [TestFixtureSetUp]
55 public void Init()
56 {
57
58 }
59
60 [TestFixtureTearDown]
61 public void TearDown()
62 {
63 if (PhysicsScene != null)
64 {
65 // The Dispose() will also free any physical objects in the scene
66 PhysicsScene.Dispose();
67 PhysicsScene = null;
68 }
69 }
70
71 [TestCase(7, 2, 5f, 5f, 32, 0f)] /* default hull parameters */
72 public void GeomHullConvexDecomp( int maxDepthSplit,
73 int maxDepthSplitForSimpleShapes,
74 float concavityThresholdPercent,
75 float volumeConservationThresholdPercent,
76 int maxVertices,
77 float maxSkinWidth)
78 {
79 // Setup the physics engine to use the C# version of convex decomp
80 Dictionary<string, string> engineParams = new Dictionary<string, string>();
81 engineParams.Add("MeshSculptedPrim", "true"); // ShouldMeshSculptedPrim
82 engineParams.Add("ForceSimplePrimMeshing", "false"); // ShouldForceSimplePrimMeshing
83 engineParams.Add("UseHullsForPhysicalObjects", "true"); // ShouldUseHullsForPhysicalObjects
84 engineParams.Add("ShouldRemoveZeroWidthTriangles", "true");
85 engineParams.Add("ShouldUseBulletHACD", "false");
86 engineParams.Add("ShouldUseSingleConvexHullForPrims", "true");
87 engineParams.Add("ShouldUseGImpactShapeForPrims", "false");
88 engineParams.Add("ShouldUseAssetHulls", "true");
89
90 engineParams.Add("CSHullMaxDepthSplit", maxDepthSplit.ToString());
91 engineParams.Add("CSHullMaxDepthSplitForSimpleShapes", maxDepthSplitForSimpleShapes.ToString());
92 engineParams.Add("CSHullConcavityThresholdPercent", concavityThresholdPercent.ToString());
93 engineParams.Add("CSHullVolumeConservationThresholdPercent", volumeConservationThresholdPercent.ToString());
94 engineParams.Add("CSHullMaxVertices", maxVertices.ToString());
95 engineParams.Add("CSHullMaxSkinWidth", maxSkinWidth.ToString());
96
97 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
98
99 PrimitiveBaseShape pbs;
100 Vector3 pos;
101 Vector3 size;
102 Quaternion rot;
103 bool isPhys;
104
105 // Cylinder
106 pbs = PrimitiveBaseShape.CreateCylinder();
107 pos = new Vector3(100.0f, 100.0f, 0f);
108 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
109 ObjectInitPosition = pos;
110 size = new Vector3(2f, 2f, 2f);
111 pbs.Scale = size;
112 rot = Quaternion.Identity;
113 isPhys = true;
114 uint cylinderLocalID = 123;
115 PhysicsScene.AddPrimShape("testCylinder", pbs, pos, size, rot, isPhys, cylinderLocalID);
116 BSPrim primTypeCylinder = (BSPrim)PhysicsScene.PhysObjects[cylinderLocalID];
117
118 // Hollow Cylinder
119 pbs = PrimitiveBaseShape.CreateCylinder();
120 pbs.ProfileHollow = (ushort)(0.70f * 50000);
121 pos = new Vector3(110.0f, 110.0f, 0f);
122 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
123 ObjectInitPosition = pos;
124 size = new Vector3(2f, 2f, 2f);
125 pbs.Scale = size;
126 rot = Quaternion.Identity;
127 isPhys = true;
128 uint hollowCylinderLocalID = 124;
129 PhysicsScene.AddPrimShape("testHollowCylinder", pbs, pos, size, rot, isPhys, hollowCylinderLocalID);
130 BSPrim primTypeHollowCylinder = (BSPrim)PhysicsScene.PhysObjects[hollowCylinderLocalID];
131
132 // Torus
133 // ProfileCurve = Circle, PathCurve = Curve1
134 pbs = PrimitiveBaseShape.CreateSphere();
135 pbs.ProfileShape = (byte)ProfileShape.Circle;
136 pbs.PathCurve = (byte)Extrusion.Curve1;
137 pbs.PathScaleX = 100; // default hollow info as set in the viewer
138 pbs.PathScaleY = (int)(.25f / 0.01f) + 200;
139 pos = new Vector3(120.0f, 120.0f, 0f);
140 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
141 ObjectInitPosition = pos;
142 size = new Vector3(2f, 4f, 4f);
143 pbs.Scale = size;
144 rot = Quaternion.Identity;
145 isPhys = true;
146 uint torusLocalID = 125;
147 PhysicsScene.AddPrimShape("testTorus", pbs, pos, size, rot, isPhys, torusLocalID);
148 BSPrim primTypeTorus = (BSPrim)PhysicsScene.PhysObjects[torusLocalID];
149
150 // The actual prim shape creation happens at taint time
151 PhysicsScene.ProcessTaints();
152
153 // Check out the created hull shapes and report their characteristics
154 ReportShapeGeom(primTypeCylinder);
155 ReportShapeGeom(primTypeHollowCylinder);
156 ReportShapeGeom(primTypeTorus);
157 }
158
159 [TestCase]
160 public void GeomHullBulletHACD()
161 {
162 // Cylinder
163 // Hollow Cylinder
164 // Torus
165 }
166
167 private void ReportShapeGeom(BSPrim prim)
168 {
169 if (prim != null)
170 {
171 if (prim.PhysShape.HasPhysicalShape)
172 {
173 BSShape physShape = prim.PhysShape;
174 string shapeType = physShape.GetType().ToString();
175 switch (shapeType)
176 {
177 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeNative":
178 BSShapeNative nShape = physShape as BSShapeNative;
179 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
180 break;
181 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeMesh":
182 BSShapeMesh mShape = physShape as BSShapeMesh;
183 prim.PhysScene.DetailLog("{0}, mesh, shapeInfo={1}", prim.Name, mShape.shapeInfo);
184 break;
185 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeHull":
186 // BSShapeHull hShape = physShape as BSShapeHull;
187 // prim.PhysScene.DetailLog("{0}, hull, shapeInfo={1}", prim.Name, hShape.shapeInfo);
188 break;
189 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeConvexHull":
190 BSShapeConvexHull chShape = physShape as BSShapeConvexHull;
191 prim.PhysScene.DetailLog("{0}, convexHull, shapeInfo={1}", prim.Name, chShape.shapeInfo);
192 break;
193 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeCompound":
194 BSShapeCompound cShape = physShape as BSShapeCompound;
195 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
196 break;
197 default:
198 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
199 break;
200 }
201 }
202 }
203 }
204}
205} \ No newline at end of file