aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs1622
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs180
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1383
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs329
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs392
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs312
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs582
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs386
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs76
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1513
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs946
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs1009
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs232
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs265
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs)315
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs)245
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs)572
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs)10
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs)39
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs)4
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs)5
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSMotors.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs)246
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs)42
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs)244
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs)72
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt (renamed from OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt)249
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs)7
27 files changed, 1404 insertions, 9873 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
deleted file mode 100755
index 30a7bee..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
+++ /dev/null
@@ -1,1622 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.IO;
30using System.Text;
31
32using OpenSim.Framework;
33
34using OpenMetaverse;
35
36using BulletXNA;
37using BulletXNA.LinearMath;
38using BulletXNA.BulletCollision;
39using BulletXNA.BulletDynamics;
40using BulletXNA.BulletCollision.CollisionDispatch;
41
42namespace OpenSim.Region.Physics.BulletSPlugin
43{
44public sealed class BSAPIXNA : BSAPITemplate
45{
46private sealed class BulletWorldXNA : BulletWorld
47{
48 public DiscreteDynamicsWorld world;
49 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
50 : base(id, physScene)
51 {
52 world = xx;
53 }
54}
55
56private sealed class BulletBodyXNA : BulletBody
57{
58 public CollisionObject body;
59 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
60
61 public BulletBodyXNA(uint id, CollisionObject xx)
62 : base(id)
63 {
64 body = xx;
65 }
66 public override bool HasPhysicalBody
67 {
68 get { return body != null; }
69 }
70 public override void Clear()
71 {
72 body = null;
73 }
74 public override string AddrString
75 {
76 get { return "XNARigidBody"; }
77 }
78}
79
80private sealed class BulletShapeXNA : BulletShape
81{
82 public CollisionShape shape;
83 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
84 : base()
85 {
86 shape = xx;
87 type = typ;
88 }
89 public override bool HasPhysicalShape
90 {
91 get { return shape != null; }
92 }
93 public override void Clear()
94 {
95 shape = null;
96 }
97 public override BulletShape Clone()
98 {
99 return new BulletShapeXNA(shape, type);
100 }
101 public override bool ReferenceSame(BulletShape other)
102 {
103 BulletShapeXNA otheru = other as BulletShapeXNA;
104 return (otheru != null) && (this.shape == otheru.shape);
105
106 }
107 public override string AddrString
108 {
109 get { return "XNACollisionShape"; }
110 }
111}
112private sealed class BulletConstraintXNA : BulletConstraint
113{
114 public TypedConstraint constrain;
115 public BulletConstraintXNA(TypedConstraint xx) : base()
116 {
117 constrain = xx;
118 }
119
120 public override void Clear()
121 {
122 constrain = null;
123 }
124 public override bool HasPhysicalConstraint { get { return constrain != null; } }
125
126 // Used for log messages for a unique display of the memory/object allocated to this instance
127 public override string AddrString
128 {
129 get { return "XNAConstraint"; }
130 }
131}
132
133 private static int m_collisionsThisFrame;
134 private BSScene PhysicsScene { get; set; }
135
136 public override string BulletEngineName { get { return "BulletXNA"; } }
137 public override string BulletEngineVersion { get; protected set; }
138
139 public BSAPIXNA(string paramName, BSScene physScene)
140 {
141 PhysicsScene = physScene;
142 }
143
144 /// <summary>
145 ///
146 /// </summary>
147 /// <param name="p"></param>
148 /// <param name="p_2"></param>
149 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
150 {
151 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
152 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
153 world.RemoveRigidBody(body);
154 return true;
155 }
156
157 public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
158 {
159 /* TODO */
160 return false;
161 }
162
163 public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
164 {
165 /* TODO */
166 return false;
167 }
168
169 public override void SetRestitution(BulletBody pBody, float pRestitution)
170 {
171 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
172 body.SetRestitution(pRestitution);
173 }
174
175 public override int GetShapeType(BulletShape pShape)
176 {
177 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
178 return (int)shape.GetShapeType();
179 }
180 public override void SetMargin(BulletShape pShape, float pMargin)
181 {
182 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
183 shape.SetMargin(pMargin);
184 }
185
186 public override float GetMargin(BulletShape pShape)
187 {
188 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
189 return shape.GetMargin();
190 }
191
192 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
193 {
194 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
195 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
196 shape.SetLocalScaling(ref vec);
197
198 }
199
200 public override void SetContactProcessingThreshold(BulletBody pBody, float contactprocessingthreshold)
201 {
202 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
203 body.SetContactProcessingThreshold(contactprocessingthreshold);
204 }
205
206 public override void SetCcdMotionThreshold(BulletBody pBody, float pccdMotionThreashold)
207 {
208 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
209 body.SetCcdMotionThreshold(pccdMotionThreashold);
210 }
211
212 public override void SetCcdSweptSphereRadius(BulletBody pBody, float pCcdSweptSphereRadius)
213 {
214 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
215 body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
216 }
217
218 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
219 {
220 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
221 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
222 }
223
224 public override CollisionFlags AddToCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags)
225 {
226 CollisionObject body = ((BulletBodyXNA)pBody).body;
227 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
228 existingcollisionFlags |= pcollisionFlags;
229 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
230 return (CollisionFlags) (uint) existingcollisionFlags;
231 }
232
233 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
234 {
235 // Bullet resets several variables when an object is added to the world. In particular,
236 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
237 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
238 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
239 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
240
241 IndexedMatrix origPos = body.GetWorldTransform();
242 IndexedVector3 origGrav = body.GetGravity();
243
244 //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE))
245
246 world.AddRigidBody(body);
247
248 body.SetWorldTransform(origPos);
249 body.SetGravity(origGrav);
250
251 pBody.ApplyCollisionMask(pWorld.physicsScene);
252
253 //if (body.GetBroadphaseHandle() != null)
254 // world.UpdateSingleAabb(body);
255 return true;
256 }
257
258 public override void ForceActivationState(BulletBody pBody, ActivationState pActivationState)
259 {
260 CollisionObject body = ((BulletBodyXNA)pBody).body;
261 body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
262 }
263
264 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pBody)
265 {
266 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
267 CollisionObject body = ((BulletBodyXNA)pBody).body;
268 world.UpdateSingleAabb(body);
269 }
270
271 public override void UpdateAabbs(BulletWorld world) { /* TODO */ }
272 public override bool GetForceUpdateAllAabbs(BulletWorld world) { /* TODO */ return false; }
273 public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) { /* TODO */ }
274
275 public override bool SetCollisionGroupMask(BulletBody pBody, uint pGroup, uint pMask)
276 {
277 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
278 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
279 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
280 if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0)
281 return false;
282 return true;
283 }
284
285 public override void ClearAllForces(BulletBody pBody)
286 {
287 CollisionObject body = ((BulletBodyXNA)pBody).body;
288 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
289 body.SetInterpolationLinearVelocity(ref zeroVector);
290 body.SetInterpolationAngularVelocity(ref zeroVector);
291 IndexedMatrix bodytransform = body.GetWorldTransform();
292
293 body.SetInterpolationWorldTransform(ref bodytransform);
294
295 if (body is RigidBody)
296 {
297 RigidBody rigidbody = body as RigidBody;
298 rigidbody.SetLinearVelocity(zeroVector);
299 rigidbody.SetAngularVelocity(zeroVector);
300 rigidbody.ClearForces();
301 }
302 }
303
304 public override void SetInterpolationAngularVelocity(BulletBody pBody, Vector3 pVector3)
305 {
306 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
307 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
308 body.SetInterpolationAngularVelocity(ref vec);
309 }
310
311 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
312 {
313 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
314 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
315 body.SetAngularVelocity(ref vec);
316 }
317 public override Vector3 GetTotalForce(BulletBody pBody)
318 {
319 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
320 IndexedVector3 iv3 = body.GetTotalForce();
321 return new Vector3(iv3.X, iv3.Y, iv3.Z);
322 }
323 public override Vector3 GetTotalTorque(BulletBody pBody)
324 {
325 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
326 IndexedVector3 iv3 = body.GetTotalTorque();
327 return new Vector3(iv3.X, iv3.Y, iv3.Z);
328 }
329 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
330 {
331 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
332 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
333 return new Vector3(iv3.X, iv3.Y, iv3.Z);
334 }
335 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
336 {
337 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
338 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
339 body.SetInvInertiaDiagLocal(ref iv3);
340 }
341 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
342 {
343 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
344 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
345 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
346 body.ApplyForce(ref forceiv3, ref posiv3);
347 }
348 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
349 {
350 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
351 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
352 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
353 body.ApplyImpulse(ref impiv3, ref posiv3);
354 }
355
356 public override void ClearForces(BulletBody pBody)
357 {
358 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
359 body.ClearForces();
360 }
361
362 public override void SetTranslation(BulletBody pBody, Vector3 _position, Quaternion _orientation)
363 {
364 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
365 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
366 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
367 _orientation.W);
368 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
369 mat._origin = vposition;
370 body.SetWorldTransform(mat);
371
372 }
373
374 public override Vector3 GetPosition(BulletBody pBody)
375 {
376 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
377 IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin;
378 return new Vector3(pos.X, pos.Y, pos.Z);
379 }
380
381 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
382 {
383 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
384 IndexedVector3 inertia = IndexedVector3.Zero;
385 shape.CalculateLocalInertia(pphysMass, out inertia);
386 return new Vector3(inertia.X, inertia.Y, inertia.Z);
387 }
388
389 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
390 {
391 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
392 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
393 body.SetMassProps(pphysMass, inertia);
394 }
395
396
397 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
398 {
399 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
400 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
401 body.SetTotalForce(ref force);
402 }
403
404 public override void SetFriction(BulletBody pBody, float _currentFriction)
405 {
406 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
407 body.SetFriction(_currentFriction);
408 }
409
410 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
411 {
412 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
413 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
414 body.SetLinearVelocity(velocity);
415 }
416
417 public override void Activate(BulletBody pBody, bool pforceactivation)
418 {
419 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
420 body.Activate(pforceactivation);
421
422 }
423
424 public override Quaternion GetOrientation(BulletBody pBody)
425 {
426 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
427 IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation();
428 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
429 }
430
431 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags)
432 {
433 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
434 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
435 existingcollisionFlags &= ~pcollisionFlags;
436 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
437 return (CollisionFlags)(uint)existingcollisionFlags;
438 }
439
440 public override float GetCcdMotionThreshold(BulletBody obj) { /* TODO */ return 0f; }
441
442 public override float GetCcdSweptSphereRadius(BulletBody obj) { /* TODO */ return 0f; }
443
444 public override IntPtr GetUserPointer(BulletBody obj) { /* TODO */ return IntPtr.Zero; }
445
446 public override void SetUserPointer(BulletBody obj, IntPtr val) { /* TODO */ }
447
448 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
449 {
450 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
451 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
452 body.SetGravity(gravity);
453 }
454
455 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
456 {
457 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
458 TypedConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain;
459 world.RemoveConstraint(constraint);
460 return true;
461 }
462
463 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
464 {
465 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
466 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
467 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
468 constraint.SetLinearLowerLimit(lowlimit);
469 constraint.SetLinearUpperLimit(highlimit);
470 return true;
471 }
472
473 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
474 {
475 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
476 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
477 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
478 constraint.SetAngularLowerLimit(lowlimit);
479 constraint.SetAngularUpperLimit(highlimit);
480 return true;
481 }
482
483 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
484 {
485 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
486 constraint.SetOverrideNumSolverIterations((int)cnt);
487 }
488
489 public override bool CalculateTransforms(BulletConstraint pConstraint)
490 {
491 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
492 constraint.CalculateTransforms();
493 return true;
494 }
495
496 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
497 {
498 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
499 constraint.SetEnabled((p_2 == 0) ? false : true);
500 }
501
502
503 //BulletSimAPI.Create6DofConstraint(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
504 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
505
506 {
507 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
508 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody;
509 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody;
510 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
511 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
512 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
513 frame1._origin = frame1v;
514
515 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
516 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
517 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
518 frame2._origin = frame1v;
519
520 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
521 puseLinearReferenceFrameA);
522 consttr.CalculateTransforms();
523 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
524
525 return new BulletConstraintXNA(consttr);
526 }
527
528
529 /// <summary>
530 ///
531 /// </summary>
532 /// <param name="pWorld"></param>
533 /// <param name="pBody1"></param>
534 /// <param name="pBody2"></param>
535 /// <param name="pjoinPoint"></param>
536 /// <param name="puseLinearReferenceFrameA"></param>
537 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
538 /// <returns></returns>
539 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
540 {
541 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
542 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody;
543 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody;
544 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
545 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
546
547 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
548 IndexedMatrix mat = IndexedMatrix.Identity;
549 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
550 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
551 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
552
553 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
554 consttr.CalculateTransforms();
555 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
556
557 return new BulletConstraintXNA(consttr);
558 }
559 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
560 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
561 {
562 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
563 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
564 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
565 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
566 frame1._origin = frame1v;
567
568 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
569 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
570 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
571 frame2._origin = frame1v;
572 constraint.SetFrames(ref frame1, ref frame2);
573 return true;
574 }
575
576 public override Vector3 GetLinearVelocity(BulletBody pBody)
577 {
578 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
579 IndexedVector3 iv3 = body.GetLinearVelocity();
580 return new Vector3(iv3.X, iv3.Y, iv3.Z);
581 }
582 public override Vector3 GetAngularVelocity(BulletBody pBody)
583 {
584 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
585 IndexedVector3 iv3 = body.GetAngularVelocity();
586 return new Vector3(iv3.X, iv3.Y, iv3.Z);
587 }
588 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
589 {
590 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
591 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
592 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
593 return new Vector3(iv3.X, iv3.Y, iv3.Z);
594 }
595 public override void Translate(BulletBody pBody, Vector3 trans)
596 {
597 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
598 }
599 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
600 {
601 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
602 body.UpdateDeactivation(timeStep);
603 }
604
605 public override bool WantsSleeping(BulletBody pBody)
606 {
607 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
608 return body.WantsSleeping();
609 }
610
611 public override void SetAngularFactor(BulletBody pBody, float factor)
612 {
613 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
614 body.SetAngularFactor(factor);
615 }
616
617 public override Vector3 GetAngularFactor(BulletBody pBody)
618 {
619 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
620 IndexedVector3 iv3 = body.GetAngularFactor();
621 return new Vector3(iv3.X, iv3.Y, iv3.Z);
622 }
623
624 public override bool IsInWorld(BulletWorld pWorld, BulletBody pBody)
625 {
626 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
627 CollisionObject body = ((BulletBodyXNA)pBody).body;
628 return world.IsInWorld(body);
629 }
630
631 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstrain)
632 {
633 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
634 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain;
635 body.AddConstraintRef(constrain);
636 }
637
638 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstrain)
639 {
640 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
641 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain;
642 body.RemoveConstraintRef(constrain);
643 }
644
645 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
646 {
647 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
648 return new BulletConstraintXNA(body.GetConstraintRef(index));
649 }
650
651 public override int GetNumConstraintRefs(BulletBody pBody)
652 {
653 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
654 return body.GetNumConstraintRefs();
655 }
656
657 public override void SetInterpolationLinearVelocity(BulletBody pBody, Vector3 VehicleVelocity)
658 {
659 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
660 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
661 body.SetInterpolationLinearVelocity(ref velocity);
662 }
663
664 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
665 {
666 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
667 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
668 return true;
669 }
670 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
671 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
672 {
673 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
674 constraint.SetBreakingImpulseThreshold(threshold);
675 return true;
676 }
677 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
678 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
679 {
680 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
681 float lineardamping = body.GetLinearDamping();
682 body.SetDamping(lineardamping, angularDamping);
683
684 }
685
686 public override void UpdateInertiaTensor(BulletBody pBody)
687 {
688 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
689 body.UpdateInertiaTensor();
690 }
691
692 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
693 {
694 CompoundShape shape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape;
695 shape.RecalculateLocalAabb();
696 }
697
698 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
699 public override CollisionFlags GetCollisionFlags(BulletBody pBody)
700 {
701 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
702 uint flags = (uint)body.GetCollisionFlags();
703 return (CollisionFlags) flags;
704 }
705
706 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
707 {
708 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
709 body.SetDamping(pLinear, pAngular);
710 }
711 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
712 public override void SetDeactivationTime(BulletBody pBody, float pDeactivationTime)
713 {
714 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
715 body.SetDeactivationTime(pDeactivationTime);
716 }
717 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
718 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
719 {
720 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
721 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
722 }
723
724 public override CollisionObjectTypes GetBodyType(BulletBody pBody)
725 {
726 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
727 return (CollisionObjectTypes)(int) body.GetInternalType();
728 }
729
730 public override void ApplyGravity(BulletBody obj) { /* TODO */ }
731
732 public override Vector3 GetGravity(BulletBody obj) { /* TODO */ return Vector3.Zero; }
733
734 public override void SetLinearDamping(BulletBody obj, float lin_damping) { /* TODO */ }
735
736 public override float GetLinearDamping(BulletBody obj) { /* TODO */ return 0f; }
737
738 public override float GetAngularDamping(BulletBody obj) { /* TODO */ return 0f; }
739
740 public override float GetLinearSleepingThreshold(BulletBody obj) { /* TODO */ return 0f; }
741
742 public override void ApplyDamping(BulletBody obj, float timeStep) { /* TODO */ }
743
744 public override Vector3 GetLinearFactor(BulletBody obj) { /* TODO */ return Vector3.Zero; }
745
746 public override void SetLinearFactor(BulletBody obj, Vector3 factor) { /* TODO */ }
747
748 public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) { /* TODO */ }
749
750 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
751 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
752 {
753 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
754 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
755 body.ApplyCentralForce(ref fSum);
756 }
757 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
758 {
759 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
760 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
761 body.ApplyCentralImpulse(ref fSum);
762 }
763 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
764 {
765 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
766 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
767 body.ApplyTorque(ref fSum);
768 }
769 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
770 {
771 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
772 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
773 body.ApplyTorqueImpulse(ref fSum);
774 }
775
776 public override void DumpRigidBody(BulletWorld p, BulletBody p_2)
777 {
778 //TODO:
779 }
780
781 public override void DumpCollisionShape(BulletWorld p, BulletShape p_2)
782 {
783 //TODO:
784 }
785 public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
786 {
787 //TODO:
788 }
789
790 public override void DumpActivationInfo(BulletWorld world)
791 {
792 //TODO:
793 }
794
795 public override void DumpAllInfo(BulletWorld world)
796 {
797 //TODO:
798 }
799
800 public override void DumpPhysicsStatistics(BulletWorld world)
801 {
802 //TODO:
803 }
804
805 public override void DestroyObject(BulletWorld p, BulletBody p_2)
806 {
807 //TODO:
808 }
809
810 public override void Shutdown(BulletWorld pWorld)
811 {
812 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
813 world.Cleanup();
814 }
815
816 public override BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id)
817 {
818 return null;
819 }
820
821 public override bool DeleteCollisionShape(BulletWorld p, BulletShape p_2)
822 {
823 //TODO:
824 return false;
825 }
826 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
827
828 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
829 {
830 CollisionWorld world = ((BulletWorldXNA)pWorld).world;
831 IndexedMatrix mat =
832 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
833 pRawOrientation.Z, pRawOrientation.W));
834 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
835 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
836 //UpdateSingleAabb(world, shape);
837 // TODO: Feed Update array into null
838 RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero);
839
840 body.SetUserPointer(pLocalID);
841 return new BulletBodyXNA(pLocalID, body);
842 }
843
844
845 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
846 {
847
848 IndexedMatrix mat =
849 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
850 pRawOrientation.Z, pRawOrientation.W));
851 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
852
853 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
854
855 // TODO: Feed Update array into null
856 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
857 body.SetWorldTransform(mat);
858 body.SetUserPointer(pLocalID);
859 return new BulletBodyXNA(pLocalID, body);
860 }
861 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
862 public override CollisionFlags SetCollisionFlags(BulletBody pBody, CollisionFlags collisionFlags)
863 {
864 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
865 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
866 return (CollisionFlags)body.GetCollisionFlags();
867 }
868
869 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return Vector3.Zero; }
870 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
871 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
872 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
873 public override bool IsStaticObject(BulletBody pBody) { /* TODO */ return false; }
874 public override bool IsKinematicObject(BulletBody pBody) { /* TODO */ return false; }
875 public override bool IsStaticOrKinematicObject(BulletBody pBody) { /* TODO */ return false; }
876 public override bool HasContactResponse(BulletBody pBody) { /* TODO */ return false; }
877 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
878 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
879 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
880 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
881 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
882 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
883 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
884 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
885
886 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
887 public override void SetHitFraction(BulletBody pBody, float pHitFraction)
888 {
889 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
890 body.SetHitFraction(pHitFraction);
891 }
892 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
893 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
894 {
895 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
896 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
897 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
898 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
899 capsuleShapeZ.SetLocalScaling(ref scale);
900
901 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
902 }
903
904 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
905 int maxCollisions, ref CollisionDesc[] collisionArray,
906 int maxUpdates, ref EntityProperties[] updateArray
907 )
908 {
909 /* TODO */
910 return new BulletWorldXNA(1, null, null);
911 }
912
913 private static object Initialize2(Vector3 worldExtent,
914 ConfigurationParameters[] o,
915 int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray,
916 int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray,
917 object mDebugLogCallbackHandle)
918 {
919 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
920
921 p.angularDamping = o[0].XangularDamping;
922 p.defaultFriction = o[0].defaultFriction;
923 p.defaultFriction = o[0].defaultFriction;
924 p.defaultDensity = o[0].defaultDensity;
925 p.defaultRestitution = o[0].defaultRestitution;
926 p.collisionMargin = o[0].collisionMargin;
927 p.gravity = o[0].gravity;
928
929 p.linearDamping = o[0].XlinearDamping;
930 p.angularDamping = o[0].XangularDamping;
931 p.deactivationTime = o[0].XdeactivationTime;
932 p.linearSleepingThreshold = o[0].XlinearSleepingThreshold;
933 p.angularSleepingThreshold = o[0].XangularSleepingThreshold;
934 p.ccdMotionThreshold = o[0].XccdMotionThreshold;
935 p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius;
936 p.contactProcessingThreshold = o[0].XcontactProcessingThreshold;
937
938 p.terrainImplementation = o[0].XterrainImplementation;
939 p.terrainFriction = o[0].XterrainFriction;
940
941 p.terrainHitFraction = o[0].XterrainHitFraction;
942 p.terrainRestitution = o[0].XterrainRestitution;
943 p.terrainCollisionMargin = o[0].XterrainCollisionMargin;
944
945 p.avatarFriction = o[0].XavatarFriction;
946 p.avatarStandingFriction = o[0].XavatarStandingFriction;
947 p.avatarDensity = o[0].XavatarDensity;
948 p.avatarRestitution = o[0].XavatarRestitution;
949 p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth;
950 p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth;
951 p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight;
952 p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold;
953
954 p.vehicleAngularDamping = o[0].XvehicleAngularDamping;
955
956 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
957 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
958 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
959 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
960 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
961 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
962 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
963 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
964
965 p.linksetImplementation = o[0].XlinksetImplementation;
966 p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset;
967 p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor;
968 p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel;
969 p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce;
970 p.linkConstraintERP = o[0].XlinkConstraintERP;
971 p.linkConstraintCFM = o[0].XlinkConstraintCFM;
972 p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations;
973 p.physicsLoggingFrames = o[0].XphysicsLoggingFrames;
974 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
975
976 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
977 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
978
979
980 if (p.maxPersistantManifoldPoolSize > 0)
981 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
982 if (p.shouldDisableContactPoolDynamicAllocation !=0)
983 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
984 //if (p.maxCollisionAlgorithmPoolSize >0 )
985
986 DbvtBroadphase m_broadphase = new DbvtBroadphase();
987 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
988 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
989
990 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
991 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
992
993 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
994
995 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
996 world.UpdatedObjects = updateArray;
997 world.UpdatedCollisions = collisionArray;
998 world.WorldSettings.Params = p;
999 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
1000 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
1001 if (p.shouldRandomizeSolverOrder != 0)
1002 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
1003
1004 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
1005 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
1006
1007 if (p.shouldEnableFrictionCaching != 0)
1008 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1009
1010 if (p.numberOfSolverIterations > 0)
1011 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
1012
1013
1014 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
1015 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
1016 world.GetSolverInfo().m_globalCfm = 0.0f;
1017 world.GetSolverInfo().m_tau = 0.6f;
1018 world.GetSolverInfo().m_friction = 0.3f;
1019 world.GetSolverInfo().m_maxErrorReduction = 20f;
1020 world.GetSolverInfo().m_numIterations = 10;
1021 world.GetSolverInfo().m_erp = 0.2f;
1022 world.GetSolverInfo().m_erp2 = 0.1f;
1023 world.GetSolverInfo().m_sor = 1.0f;
1024 world.GetSolverInfo().m_splitImpulse = false;
1025 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1026 world.GetSolverInfo().m_linearSlop = 0.0f;
1027 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1028 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1029 world.SetForceUpdateAllAabbs(true);
1030
1031
1032 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1033
1034 return world;
1035 }
1036 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1037 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1038 {
1039 Generic6DofConstraint constrain = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
1040 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1041 {
1042 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1043 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1044 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1045 }
1046 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1047 {
1048 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1049 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1050 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1051 }
1052 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1053 {
1054 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1055 }
1056 return true;
1057 }
1058
1059 public override bool PushUpdate(BulletBody pCollisionObject)
1060 {
1061 bool ret = false;
1062 RigidBody rb = ((BulletBodyXNA)pCollisionObject).rigidBody;
1063 if (rb != null)
1064 {
1065 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1066 if (sms != null)
1067 {
1068 IndexedMatrix wt = IndexedMatrix.Identity;
1069 sms.GetWorldTransform(out wt);
1070 sms.SetWorldTransform(ref wt, true);
1071 ret = true;
1072 }
1073 }
1074 return ret;
1075
1076 }
1077
1078 public override float GetAngularMotionDisc(BulletShape pShape)
1079 {
1080 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1081 return shape.GetAngularMotionDisc();
1082 }
1083 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1084 {
1085 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1086 return shape.GetContactBreakingThreshold(defaultFactor);
1087 }
1088 public override bool IsCompound(BulletShape pShape)
1089 {
1090 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1091 return shape.IsCompound();
1092 }
1093 public override bool IsSoftBody(BulletShape pShape)
1094 {
1095 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1096 return shape.IsSoftBody();
1097 }
1098 public override bool IsPolyhedral(BulletShape pShape)
1099 {
1100 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1101 return shape.IsPolyhedral();
1102 }
1103 public override bool IsConvex2d(BulletShape pShape)
1104 {
1105 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1106 return shape.IsConvex2d();
1107 }
1108 public override bool IsConvex(BulletShape pShape)
1109 {
1110 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1111 return shape.IsConvex();
1112 }
1113 public override bool IsNonMoving(BulletShape pShape)
1114 {
1115 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1116 return shape.IsNonMoving();
1117 }
1118 public override bool IsConcave(BulletShape pShape)
1119 {
1120 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1121 return shape.IsConcave();
1122 }
1123 public override bool IsInfinite(BulletShape pShape)
1124 {
1125 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1126 return shape.IsInfinite();
1127 }
1128 public override bool IsNativeShape(BulletShape pShape)
1129 {
1130 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1131 bool ret;
1132 switch (shape.GetShapeType())
1133 {
1134 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1135 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1136 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1137 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1138 ret = true;
1139 break;
1140 default:
1141 ret = false;
1142 break;
1143 }
1144 return ret;
1145 }
1146
1147 public override void SetShapeCollisionMargin(BulletShape shape, float margin) { /* TODO */ }
1148
1149 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1150 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1151 {
1152 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1153 IndexedMatrix bodyTransform = new IndexedMatrix();
1154 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1155 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1156 GhostObject gObj = new PairCachingGhostObject();
1157 gObj.SetWorldTransform(bodyTransform);
1158 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1159 gObj.SetCollisionShape(shape);
1160 gObj.SetUserPointer(pLocalID);
1161 // TODO: Add to Special CollisionObjects!
1162 return new BulletBodyXNA(pLocalID, gObj);
1163 }
1164
1165 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pObj, BulletShape pShape)
1166 {
1167 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1168 CollisionObject obj = ((BulletBodyXNA)pObj).body;
1169 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1170 obj.SetCollisionShape(shape);
1171
1172 }
1173 public override BulletShape GetCollisionShape(BulletBody obj) { /* TODO */ return null; }
1174
1175 //(PhysicsScene.World.ptr, nativeShapeData)
1176 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1177 {
1178 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1179 CollisionShape shape = null;
1180 switch (pShapeData.Type)
1181 {
1182 case BSPhysicsShapeType.SHAPE_BOX:
1183 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1184 break;
1185 case BSPhysicsShapeType.SHAPE_CONE:
1186 shape = new ConeShapeZ(0.5f, 1.0f);
1187 break;
1188 case BSPhysicsShapeType.SHAPE_CYLINDER:
1189 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1190 break;
1191 case BSPhysicsShapeType.SHAPE_SPHERE:
1192 shape = new SphereShape(0.5f);
1193 break;
1194
1195 }
1196 if (shape != null)
1197 {
1198 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1199 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1200 shape.SetLocalScaling(ref scaling);
1201
1202 }
1203 return new BulletShapeXNA(shape, pShapeData.Type);
1204 }
1205 //PhysicsScene.World.ptr, false
1206 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1207 {
1208 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1209 }
1210
1211 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1212 {
1213 CompoundShape compoundshape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape;
1214 return compoundshape.GetNumChildShapes();
1215 }
1216 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1217 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1218 {
1219 IndexedMatrix relativeTransform = new IndexedMatrix();
1220 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape;
1221 CollisionShape addshape = ((BulletShapeXNA)paddShape).shape;
1222
1223 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1224 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1225 compoundshape.AddChildShape(ref relativeTransform, addshape);
1226
1227 }
1228
1229 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1230 {
1231 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape;
1232 CollisionShape ret = null;
1233 ret = compoundshape.GetChildShape(pii);
1234 compoundshape.RemoveChildShapeByIndex(pii);
1235 return new BulletShapeXNA(ret, BSPhysicsShapeType.SHAPE_UNKNOWN);
1236 }
1237
1238 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { /* TODO */ return null; }
1239 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1240
1241 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1242 {
1243 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1244 m_planeshape.SetMargin(pcollisionMargin);
1245 m_planeshape.SetUserPointer(pLocalId);
1246 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1247 }
1248
1249 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1250 {
1251 HingeConstraint constrain = null;
1252 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1253 RigidBody rb1 = ((BulletBodyXNA)pBody1).rigidBody;
1254 RigidBody rb2 = ((BulletBodyXNA)ppBody2).rigidBody;
1255 if (rb1 != null && rb2 != null)
1256 {
1257 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1258 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1259 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1260 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1261 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1262 }
1263 return new BulletConstraintXNA(constrain);
1264 }
1265
1266 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
1267 {
1268 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1269 CompoundShape compoundshape = new CompoundShape(false);
1270
1271 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1272 int ii = 1;
1273
1274 for (int i = 0; i < pHullCount; i++)
1275 {
1276 int vertexCount = (int) pConvHulls[ii];
1277
1278 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1279 IndexedMatrix childTrans = IndexedMatrix.Identity;
1280 childTrans._origin = centroid;
1281
1282 List<IndexedVector3> virts = new List<IndexedVector3>();
1283 int ender = ((ii + 4) + (vertexCount*3));
1284 for (int iii = ii + 4; iii < ender; iii+=3)
1285 {
1286
1287 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1288 }
1289 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1290 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1291 compoundshape.AddChildShape(ref childTrans, convexShape);
1292 ii += (vertexCount*3 + 4);
1293 }
1294
1295 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1296 }
1297
1298 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) { /* TODO */ return null; }
1299
1300 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1301 {
1302 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1303
1304 for (int iter = 0; iter < pVerticesCount; iter++)
1305 {
1306 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1307 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1308 }
1309
1310 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1311 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1312 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1313 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1314 IndexedMesh mesh = new IndexedMesh();
1315 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1316 mesh.m_numTriangles = pIndicesCount/3;
1317 mesh.m_numVertices = pVerticesCount;
1318 mesh.m_triangleIndexBase = indicesarr;
1319 mesh.m_vertexBase = vertices;
1320 mesh.m_vertexStride = 3;
1321 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1322 mesh.m_triangleIndexStride = 3;
1323
1324 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1325 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1326 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1327 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1328 // world.UpdateSingleAabb(meshShape);
1329 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1330
1331 }
1332 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1333 {
1334
1335 String fileName = "objTest3.raw";
1336 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1337 StreamWriter sw = new StreamWriter(completePath);
1338 IndexedMesh mesh = new IndexedMesh();
1339
1340 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1341 mesh.m_numTriangles = pIndicesCount / 3;
1342 mesh.m_numVertices = pVerticesCount;
1343 mesh.m_triangleIndexBase = indices;
1344 mesh.m_vertexBase = vertices;
1345 mesh.m_vertexStride = 3;
1346 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1347 mesh.m_triangleIndexStride = 3;
1348
1349 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1350 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1351
1352
1353
1354 for (int i = 0; i < pVerticesCount; i++)
1355 {
1356
1357 string s = vertices[indices[i * 3]].ToString("0.0000");
1358 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1359 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1360
1361 sw.Write(s + "\n");
1362 }
1363
1364 sw.Close();
1365 }
1366 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1367 {
1368
1369 String fileName = "objTest6.raw";
1370 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1371 StreamWriter sw = new StreamWriter(completePath);
1372 IndexedMesh mesh = new IndexedMesh();
1373
1374 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1375 mesh.m_numTriangles = pIndicesCount / 3;
1376 mesh.m_numVertices = pVerticesCount;
1377 mesh.m_triangleIndexBase = indices;
1378 mesh.m_vertexBase = vertices;
1379 mesh.m_vertexStride = 3;
1380 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1381 mesh.m_triangleIndexStride = 3;
1382
1383 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1384 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1385
1386
1387 sw.WriteLine("Indices");
1388 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1389 for (int iter = 0; iter < indices.Length; iter++)
1390 {
1391 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1392 }
1393 sw.WriteLine("VerticesFloats");
1394 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1395 for (int iter = 0; iter < vertices.Length; iter++)
1396 {
1397 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1398 }
1399
1400 // for (int i = 0; i < pVerticesCount; i++)
1401 // {
1402 //
1403 // string s = vertices[indices[i * 3]].ToString("0.0000");
1404 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1405 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1406 //
1407 // sw.Write(s + "\n");
1408 //}
1409
1410 sw.Close();
1411 }
1412
1413 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1414 float scaleFactor, float collisionMargin)
1415 {
1416 const int upAxis = 2;
1417 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
1418 heightMap, scaleFactor,
1419 minHeight, maxHeight, upAxis,
1420 false);
1421 terrainShape.SetMargin(collisionMargin + 0.5f);
1422 terrainShape.SetUseDiamondSubdivision(true);
1423 terrainShape.SetUserPointer(id);
1424 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
1425 }
1426
1427 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1428 {
1429 TypedConstraint tconstrain = ((BulletConstraintXNA)pConstraint).constrain;
1430 bool onOff = ponOff != 0;
1431 bool ret = false;
1432
1433 switch (tconstrain.GetConstraintType())
1434 {
1435 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1436 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
1437 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1438 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1439 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1440 ret = true;
1441 break;
1442 }
1443
1444
1445 return ret;
1446
1447 }
1448
1449 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
1450 out int updatedEntityCount, out int collidersCount)
1451 {
1452 /* TODO */
1453 updatedEntityCount = 0;
1454 collidersCount = 0;
1455 return 1;
1456 }
1457
1458 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1459 out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities,
1460 out int collidersCount, out List<BulletXNA.CollisionDesc>colliders)
1461 {
1462 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1463 out collidersCount, out colliders);
1464 return epic;
1465 }
1466
1467 private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders)
1468 {
1469 int numSimSteps = 0;
1470
1471
1472 //if (updatedEntities is null)
1473 // updatedEntities = new List<BulletXNA.EntityProperties>();
1474
1475 //if (colliders is null)
1476 // colliders = new List<BulletXNA.CollisionDesc>();
1477
1478
1479 if (pWorld is BulletWorldXNA)
1480 {
1481 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1482
1483 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1484 int updates = 0;
1485
1486 updatedEntityCount = world.UpdatedObjects.Count;
1487 updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects);
1488 updatedEntityCount = updatedEntities.Count;
1489 world.UpdatedObjects.Clear();
1490
1491
1492 collidersCount = world.UpdatedCollisions.Count;
1493 colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1494
1495 world.UpdatedCollisions.Clear();
1496 m_collisionsThisFrame = 0;
1497 int numManifolds = world.GetDispatcher().GetNumManifolds();
1498 for (int j = 0; j < numManifolds; j++)
1499 {
1500 PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1501 int numContacts = contactManifold.GetNumContacts();
1502 if (numContacts == 0)
1503 continue;
1504
1505 CollisionObject objA = contactManifold.GetBody0() as CollisionObject;
1506 CollisionObject objB = contactManifold.GetBody1() as CollisionObject;
1507
1508 ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0);
1509 IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
1510 IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
1511
1512 RecordCollision(world, objA, objB, contactPoint, contactNormal);
1513 m_collisionsThisFrame ++;
1514 if (m_collisionsThisFrame >= 9999999)
1515 break;
1516
1517
1518 }
1519
1520
1521 }
1522 else
1523 {
1524 //if (updatedEntities is null)
1525 updatedEntities = new List<BulletXNA.EntityProperties>();
1526 updatedEntityCount = 0;
1527 //if (colliders is null)
1528 colliders = new List<BulletXNA.CollisionDesc>();
1529 collidersCount = 0;
1530 }
1531 return numSimSteps;
1532 }
1533
1534 private static void RecordCollision(CollisionWorld world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm)
1535 {
1536
1537 IndexedVector3 contactNormal = norm;
1538 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
1539 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
1540 {
1541 return;
1542 }
1543 uint idA = (uint)objA.GetUserPointer();
1544 uint idB = (uint)objB.GetUserPointer();
1545 if (idA > idB)
1546 {
1547 uint temp = idA;
1548 idA = idB;
1549 idB = temp;
1550 contactNormal = -contactNormal;
1551 }
1552
1553 ulong collisionID = ((ulong) idA << 32) | idB;
1554
1555 BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc()
1556 {
1557 aID = idA,
1558 bID = idB,
1559 point = contact,
1560 normal = contactNormal
1561 };
1562 world.UpdatedCollisions.Add(cDesc);
1563 m_collisionsThisFrame++;
1564
1565
1566 }
1567 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pBody)
1568 {
1569 EntityProperties ent = new EntityProperties();
1570 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1571 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
1572 IndexedMatrix transform = body.GetWorldTransform();
1573 IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity();
1574 IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity();
1575 IndexedQuaternion rotation = transform.GetRotation();
1576 ent.Acceleration = Vector3.Zero;
1577 ent.ID = (uint)body.GetUserPointer();
1578 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
1579 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
1580 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
1581 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
1582 return ent;
1583 }
1584
1585 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ return false; }
1586
1587 public override Vector3 GetLocalScaling(BulletShape pShape)
1588 {
1589 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1590 IndexedVector3 scale = shape.GetLocalScaling();
1591 return new Vector3(scale.X,scale.Y,scale.Z);
1592 }
1593
1594 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
1595 {
1596 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1597 if (world != null)
1598 {
1599 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
1600 {
1601 CollisionObject AvoidBody = ((BulletBodyXNA)NotMe).body;
1602
1603 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
1604 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
1605 using (
1606 ClosestNotMeRayResultCallback rayCallback =
1607 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
1608 )
1609 {
1610 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
1611 if (rayCallback.HasHit())
1612 {
1613 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
1614 }
1615 return rayCallback.HasHit();
1616 }
1617 }
1618 }
1619 return false;
1620 }
1621}
1622}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
deleted file mode 100755
index 2aeff25..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
+++ /dev/null
@@ -1,180 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.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 RemoveAndDestroyConstraint(constrain);
121 ret = true;
122 }
123 }
124
125 return ret;
126 }
127
128 // The constraint MUST exist in the collection
129 public bool RemoveAndDestroyConstraint(BSConstraint constrain)
130 {
131 lock (m_constraints)
132 {
133 // remove the constraint from our collection
134 m_constraints.Remove(constrain);
135 }
136 // tell the engine that all its structures need to be freed
137 constrain.Dispose();
138 // we destroyed something
139 return true;
140 }
141
142 // Remove all constraints that reference the passed body.
143 // Return 'true' if any constraints were destroyed.
144 public bool RemoveAndDestroyConstraint(BulletBody body1)
145 {
146 List<BSConstraint> toRemove = new List<BSConstraint>();
147 uint lookingID = body1.ID;
148 lock (m_constraints)
149 {
150 foreach (BSConstraint constrain in m_constraints)
151 {
152 if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
153 {
154 toRemove.Add(constrain);
155 }
156 }
157 foreach (BSConstraint constrain in toRemove)
158 {
159 m_constraints.Remove(constrain);
160 constrain.Dispose();
161 }
162 }
163 return (toRemove.Count > 0);
164 }
165
166 public bool RecalculateAllConstraints()
167 {
168 bool ret = false;
169 lock (m_constraints)
170 {
171 foreach (BSConstraint constrain in m_constraints)
172 {
173 constrain.CalculateTransforms();
174 ret = true;
175 }
176 }
177 return ret;
178 }
179}
180}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
deleted file mode 100644
index 13c2539..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ /dev/null
@@ -1,1383 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above 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.Region.Physics.Manager;
39
40namespace OpenSim.Region.Physics.BulletSPlugin
41{
42 public sealed class BSDynamics
43 {
44 private static string LogHeader = "[BULLETSIM VEHICLE]";
45
46 private BSScene PhysicsScene { get; set; }
47 // the prim this dynamic controller belongs to
48 private BSPrim Prim { get; set; }
49
50 // mass of the vehicle fetched each time we're calles
51 private float m_vehicleMass;
52
53 // Vehicle properties
54 public Vehicle Type { get; set; }
55
56 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
57 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
58 // HOVER_TERRAIN_ONLY
59 // HOVER_GLOBAL_HEIGHT
60 // NO_DEFLECTION_UP
61 // HOVER_WATER_ONLY
62 // HOVER_UP_ONLY
63 // LIMIT_MOTOR_UP
64 // LIMIT_ROLL_ONLY
65 private Vector3 m_BlockingEndPoint = Vector3.Zero;
66 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
67 private Quaternion m_referenceFrame = Quaternion.Identity;
68
69 // Linear properties
70 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
71 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
72 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
73 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
74 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
75 private float m_linearMotorDecayTimescale = 0;
76 private float m_linearMotorTimescale = 0;
77 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
78 private Vector3 m_lastPositionVector = Vector3.Zero;
79 // private bool m_LinearMotorSetLastFrame = false;
80 // private Vector3 m_linearMotorOffset = Vector3.Zero;
81
82 //Angular properties
83 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
84 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
85 // private int m_angularMotorApply = 0; // application frame counter
86 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
87 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
88 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
89 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
90 private Vector3 m_lastAngularVelocity = Vector3.Zero;
91 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
92
93 //Deflection properties
94 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
95 private float m_angularDeflectionEfficiency = 0;
96 private float m_angularDeflectionTimescale = 0;
97 private float m_linearDeflectionEfficiency = 0;
98 private float m_linearDeflectionTimescale = 0;
99
100 //Banking properties
101 private float m_bankingEfficiency = 0;
102 private float m_bankingMix = 0;
103 private float m_bankingTimescale = 0;
104
105 //Hover and Buoyancy properties
106 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
107 private float m_VhoverHeight = 0f;
108 private float m_VhoverEfficiency = 0f;
109 private float m_VhoverTimescale = 0f;
110 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
111 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
112 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
113 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
114 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
115
116 //Attractor properties
117 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
118 private float m_verticalAttractionEfficiency = 1.0f; // damped
119 private float m_verticalAttractionCutoff = 500f; // per the documentation
120 // Timescale > cutoff means no vert attractor.
121 private float m_verticalAttractionTimescale = 510f;
122
123 // Just some recomputed constants:
124 static readonly float PIOverFour = ((float)Math.PI) / 4f;
125 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
126
127 public BSDynamics(BSScene myScene, BSPrim myPrim)
128 {
129 PhysicsScene = myScene;
130 Prim = myPrim;
131 Type = Vehicle.TYPE_NONE;
132 }
133
134 // Return 'true' if this vehicle is doing vehicle things
135 public bool IsActive
136 {
137 get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; }
138 }
139
140 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
141 {
142 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
143 switch (pParam)
144 {
145 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
146 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
147 break;
148 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
149 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
150 break;
151 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
152 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
153 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
154 break;
155 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
156 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
157 m_angularMotor.TimeScale = m_angularMotorTimescale;
158 break;
159 case Vehicle.BANKING_EFFICIENCY:
160 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
161 break;
162 case Vehicle.BANKING_MIX:
163 m_bankingMix = Math.Max(pValue, 0.01f);
164 break;
165 case Vehicle.BANKING_TIMESCALE:
166 m_bankingTimescale = Math.Max(pValue, 0.01f);
167 break;
168 case Vehicle.BUOYANCY:
169 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
170 break;
171 case Vehicle.HOVER_EFFICIENCY:
172 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
173 break;
174 case Vehicle.HOVER_HEIGHT:
175 m_VhoverHeight = pValue;
176 break;
177 case Vehicle.HOVER_TIMESCALE:
178 m_VhoverTimescale = Math.Max(pValue, 0.01f);
179 break;
180 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
181 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
182 break;
183 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
184 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
185 break;
186 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
187 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
188 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
192 m_linearMotor.TimeScale = m_linearMotorTimescale;
193 break;
194 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
195 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
196 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
197 break;
198 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
199 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
200 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
201 break;
202
203 // These are vector properties but the engine lets you use a single float value to
204 // set all of the components to the same value
205 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
206 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
207 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
208 break;
209 case Vehicle.ANGULAR_MOTOR_DIRECTION:
210 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
211 m_angularMotor.SetTarget(m_angularMotorDirection);
212 break;
213 case Vehicle.LINEAR_FRICTION_TIMESCALE:
214 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
215 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
216 break;
217 case Vehicle.LINEAR_MOTOR_DIRECTION:
218 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
219 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
220 m_linearMotor.SetTarget(m_linearMotorDirection);
221 break;
222 case Vehicle.LINEAR_MOTOR_OFFSET:
223 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
224 break;
225
226 }
227 }//end ProcessFloatVehicleParam
228
229 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
230 {
231 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
232 switch (pParam)
233 {
234 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
235 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
237 break;
238 case Vehicle.ANGULAR_MOTOR_DIRECTION:
239 // Limit requested angular speed to 2 rps= 4 pi rads/sec
240 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
241 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
242 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
243 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_angularMotor.SetTarget(m_angularMotorDirection);
245 break;
246 case Vehicle.LINEAR_FRICTION_TIMESCALE:
247 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
248 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
249 break;
250 case Vehicle.LINEAR_MOTOR_DIRECTION:
251 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
252 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 m_linearMotor.SetTarget(m_linearMotorDirection);
254 break;
255 case Vehicle.LINEAR_MOTOR_OFFSET:
256 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
257 break;
258 case Vehicle.BLOCK_EXIT:
259 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 break;
261 }
262 }//end ProcessVectorVehicleParam
263
264 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
265 {
266 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
267 switch (pParam)
268 {
269 case Vehicle.REFERENCE_FRAME:
270 m_referenceFrame = pValue;
271 break;
272 case Vehicle.ROLL_FRAME:
273 m_RollreferenceFrame = pValue;
274 break;
275 }
276 }//end ProcessRotationVehicleParam
277
278 internal void ProcessVehicleFlags(int pParam, bool remove)
279 {
280 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
281 VehicleFlag parm = (VehicleFlag)pParam;
282 if (pParam == -1)
283 m_flags = (VehicleFlag)0;
284 else
285 {
286 if (remove)
287 m_flags &= ~parm;
288 else
289 m_flags |= parm;
290 }
291 }
292
293 internal void ProcessTypeChange(Vehicle pType)
294 {
295 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
296 // Set Defaults For Type
297 Type = pType;
298 switch (pType)
299 {
300 case Vehicle.TYPE_NONE:
301 m_linearMotorDirection = Vector3.Zero;
302 m_linearMotorTimescale = 0;
303 m_linearMotorDecayTimescale = 0;
304 m_linearFrictionTimescale = new Vector3(0, 0, 0);
305
306 m_angularMotorDirection = Vector3.Zero;
307 m_angularMotorDecayTimescale = 0;
308 m_angularMotorTimescale = 0;
309 m_angularFrictionTimescale = new Vector3(0, 0, 0);
310
311 m_VhoverHeight = 0;
312 m_VhoverEfficiency = 0;
313 m_VhoverTimescale = 0;
314 m_VehicleBuoyancy = 0;
315
316 m_linearDeflectionEfficiency = 1;
317 m_linearDeflectionTimescale = 1;
318
319 m_angularDeflectionEfficiency = 0;
320 m_angularDeflectionTimescale = 1000;
321
322 m_verticalAttractionEfficiency = 0;
323 m_verticalAttractionTimescale = 0;
324
325 m_bankingEfficiency = 0;
326 m_bankingTimescale = 1000;
327 m_bankingMix = 1;
328
329 m_referenceFrame = Quaternion.Identity;
330 m_flags = (VehicleFlag)0;
331
332 break;
333
334 case Vehicle.TYPE_SLED:
335 m_linearMotorDirection = Vector3.Zero;
336 m_linearMotorTimescale = 1000;
337 m_linearMotorDecayTimescale = 120;
338 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
339
340 m_angularMotorDirection = Vector3.Zero;
341 m_angularMotorTimescale = 1000;
342 m_angularMotorDecayTimescale = 120;
343 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
344
345 m_VhoverHeight = 0;
346 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
347 m_VhoverTimescale = 10;
348 m_VehicleBuoyancy = 0;
349
350 m_linearDeflectionEfficiency = 1;
351 m_linearDeflectionTimescale = 1;
352
353 m_angularDeflectionEfficiency = 1;
354 m_angularDeflectionTimescale = 1000;
355
356 m_verticalAttractionEfficiency = 0;
357 m_verticalAttractionTimescale = 0;
358
359 m_bankingEfficiency = 0;
360 m_bankingTimescale = 10;
361 m_bankingMix = 1;
362
363 m_referenceFrame = Quaternion.Identity;
364 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
365 | VehicleFlag.HOVER_TERRAIN_ONLY
366 | VehicleFlag.HOVER_GLOBAL_HEIGHT
367 | VehicleFlag.HOVER_UP_ONLY);
368 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
369 | VehicleFlag.LIMIT_ROLL_ONLY
370 | VehicleFlag.LIMIT_MOTOR_UP);
371
372 break;
373 case Vehicle.TYPE_CAR:
374 m_linearMotorDirection = Vector3.Zero;
375 m_linearMotorTimescale = 1;
376 m_linearMotorDecayTimescale = 60;
377 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
378
379 m_angularMotorDirection = Vector3.Zero;
380 m_angularMotorTimescale = 1;
381 m_angularMotorDecayTimescale = 0.8f;
382 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
383
384 m_VhoverHeight = 0;
385 m_VhoverEfficiency = 0;
386 m_VhoverTimescale = 1000;
387 m_VehicleBuoyancy = 0;
388
389 m_linearDeflectionEfficiency = 1;
390 m_linearDeflectionTimescale = 2;
391
392 m_angularDeflectionEfficiency = 0;
393 m_angularDeflectionTimescale = 10;
394
395 m_verticalAttractionEfficiency = 1f;
396 m_verticalAttractionTimescale = 10f;
397
398 m_bankingEfficiency = -0.2f;
399 m_bankingMix = 1;
400 m_bankingTimescale = 1;
401
402 m_referenceFrame = Quaternion.Identity;
403 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
404 | VehicleFlag.HOVER_TERRAIN_ONLY
405 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
406 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
407 | VehicleFlag.LIMIT_ROLL_ONLY
408 | VehicleFlag.LIMIT_MOTOR_UP
409 | VehicleFlag.HOVER_UP_ONLY);
410 break;
411 case Vehicle.TYPE_BOAT:
412 m_linearMotorDirection = Vector3.Zero;
413 m_linearMotorTimescale = 5;
414 m_linearMotorDecayTimescale = 60;
415 m_linearFrictionTimescale = new Vector3(10, 3, 2);
416
417 m_angularMotorDirection = Vector3.Zero;
418 m_angularMotorTimescale = 4;
419 m_angularMotorDecayTimescale = 4;
420 m_angularFrictionTimescale = new Vector3(10,10,10);
421
422 m_VhoverHeight = 0;
423 m_VhoverEfficiency = 0.5f;
424 m_VhoverTimescale = 2;
425 m_VehicleBuoyancy = 1;
426
427 m_linearDeflectionEfficiency = 0.5f;
428 m_linearDeflectionTimescale = 3;
429
430 m_angularDeflectionEfficiency = 0.5f;
431 m_angularDeflectionTimescale = 5;
432
433 m_verticalAttractionEfficiency = 0.5f;
434 m_verticalAttractionTimescale = 5f;
435
436 m_bankingEfficiency = -0.3f;
437 m_bankingMix = 0.8f;
438 m_bankingTimescale = 1;
439
440 m_referenceFrame = Quaternion.Identity;
441 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
442 | VehicleFlag.HOVER_GLOBAL_HEIGHT
443 | VehicleFlag.LIMIT_ROLL_ONLY
444 | VehicleFlag.HOVER_UP_ONLY);
445 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
446 | VehicleFlag.LIMIT_MOTOR_UP
447 | VehicleFlag.HOVER_WATER_ONLY);
448 break;
449 case Vehicle.TYPE_AIRPLANE:
450 m_linearMotorDirection = Vector3.Zero;
451 m_linearMotorTimescale = 2;
452 m_linearMotorDecayTimescale = 60;
453 m_linearFrictionTimescale = new Vector3(200, 10, 5);
454
455 m_angularMotorDirection = Vector3.Zero;
456 m_angularMotorTimescale = 4;
457 m_angularMotorDecayTimescale = 4;
458 m_angularFrictionTimescale = new Vector3(20, 20, 20);
459
460 m_VhoverHeight = 0;
461 m_VhoverEfficiency = 0.5f;
462 m_VhoverTimescale = 1000;
463 m_VehicleBuoyancy = 0;
464
465 m_linearDeflectionEfficiency = 0.5f;
466 m_linearDeflectionTimescale = 3;
467
468 m_angularDeflectionEfficiency = 1;
469 m_angularDeflectionTimescale = 2;
470
471 m_verticalAttractionEfficiency = 0.9f;
472 m_verticalAttractionTimescale = 2f;
473
474 m_bankingEfficiency = 1;
475 m_bankingMix = 0.7f;
476 m_bankingTimescale = 2;
477
478 m_referenceFrame = Quaternion.Identity;
479 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
480 | VehicleFlag.HOVER_TERRAIN_ONLY
481 | VehicleFlag.HOVER_GLOBAL_HEIGHT
482 | VehicleFlag.HOVER_UP_ONLY
483 | VehicleFlag.NO_DEFLECTION_UP
484 | VehicleFlag.LIMIT_MOTOR_UP);
485 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
486 break;
487 case Vehicle.TYPE_BALLOON:
488 m_linearMotorDirection = Vector3.Zero;
489 m_linearMotorTimescale = 5;
490 m_linearFrictionTimescale = new Vector3(5, 5, 5);
491 m_linearMotorDecayTimescale = 60;
492
493 m_angularMotorDirection = Vector3.Zero;
494 m_angularMotorTimescale = 6;
495 m_angularFrictionTimescale = new Vector3(10, 10, 10);
496 m_angularMotorDecayTimescale = 10;
497
498 m_VhoverHeight = 5;
499 m_VhoverEfficiency = 0.8f;
500 m_VhoverTimescale = 10;
501 m_VehicleBuoyancy = 1;
502
503 m_linearDeflectionEfficiency = 0;
504 m_linearDeflectionTimescale = 5;
505
506 m_angularDeflectionEfficiency = 0;
507 m_angularDeflectionTimescale = 5;
508
509 m_verticalAttractionEfficiency = 1f;
510 m_verticalAttractionTimescale = 100f;
511
512 m_bankingEfficiency = 0;
513 m_bankingMix = 0.7f;
514 m_bankingTimescale = 5;
515
516 m_referenceFrame = Quaternion.Identity;
517
518 m_referenceFrame = Quaternion.Identity;
519 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
520 | VehicleFlag.HOVER_TERRAIN_ONLY
521 | VehicleFlag.HOVER_UP_ONLY
522 | VehicleFlag.NO_DEFLECTION_UP
523 | VehicleFlag.LIMIT_MOTOR_UP);
524 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
525 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
526 break;
527 }
528
529 // Update any physical parameters based on this type.
530 Refresh();
531
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
534 1f);
535 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
536
537 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
538 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
539 1f);
540 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
541
542 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
543 BSMotor.Infinite, BSMotor.InfiniteVector,
544 m_verticalAttractionEfficiency);
545 // Z goes away and we keep X and Y
546 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
547 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
548 }
549
550 // Some of the properties of this prim may have changed.
551 // Do any updating needed for a vehicle
552 public void Refresh()
553 {
554 if (IsActive)
555 {
556 // Remember the mass so we don't have to fetch it every step
557 m_vehicleMass = Prim.Linkset.LinksetMass;
558
559 // Friction affects are handled by this vehicle code
560 float friction = 0f;
561 PhysicsScene.PE.SetFriction(Prim.PhysBody, friction);
562
563 // Moderate angular movement introduced by Bullet.
564 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
565 // Maybe compute linear and angular factor and damping from params.
566 float angularDamping = BSParam.VehicleAngularDamping;
567 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping);
568
569 // Vehicles report collision events so we know when it's on the ground
570 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
571
572 Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass);
573 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, localInertia);
574 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody);
575
576 Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy);
577 PhysicsScene.PE.SetGravity(Prim.PhysBody, grav);
578
579 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}",
580 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping);
581 }
582 else
583 {
584 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
585 }
586 }
587
588 public bool RemoveBodyDependencies(BSPhysObject prim)
589 {
590 // If active, we need to add our properties back when the body is rebuilt.
591 return IsActive;
592 }
593
594 public void RestoreBodyDependencies(BSPhysObject prim)
595 {
596 if (Prim.LocalID != prim.LocalID)
597 {
598 // The call should be on us by our prim. Error if not.
599 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}",
600 LogHeader, prim.LocalID, Prim.LocalID);
601 return;
602 }
603 Refresh();
604 }
605
606 #region Known vehicle value functions
607 // Vehicle physical parameters that we buffer from constant getting and setting.
608 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
609 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
610 // This does two things: 1) saves continuious calls into unmanaged code, and
611 // 2) signals when a physics property update must happen back to the simulator
612 // to update values modified for the vehicle.
613 private int m_knownChanged;
614 private int m_knownHas;
615 private float m_knownTerrainHeight;
616 private float m_knownWaterLevel;
617 private Vector3 m_knownPosition;
618 private Vector3 m_knownVelocity;
619 private Vector3 m_knownForce;
620 private Quaternion m_knownOrientation;
621 private Vector3 m_knownRotationalVelocity;
622 private Vector3 m_knownRotationalForce;
623 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
624
625 private const int m_knownChangedPosition = 1 << 0;
626 private const int m_knownChangedVelocity = 1 << 1;
627 private const int m_knownChangedForce = 1 << 2;
628 private const int m_knownChangedOrientation = 1 << 3;
629 private const int m_knownChangedRotationalVelocity = 1 << 4;
630 private const int m_knownChangedRotationalForce = 1 << 5;
631 private const int m_knownChangedTerrainHeight = 1 << 6;
632 private const int m_knownChangedWaterLevel = 1 << 7;
633 private const int m_knownChangedForwardVelocity = 1 << 8;
634
635 private void ForgetKnownVehicleProperties()
636 {
637 m_knownHas = 0;
638 m_knownChanged = 0;
639 }
640 // Push all the changed values back into the physics engine
641 private void PushKnownChanged()
642 {
643 if (m_knownChanged != 0)
644 {
645 if ((m_knownChanged & m_knownChangedPosition) != 0)
646 Prim.ForcePosition = m_knownPosition;
647
648 if ((m_knownChanged & m_knownChangedOrientation) != 0)
649 Prim.ForceOrientation = m_knownOrientation;
650
651 if ((m_knownChanged & m_knownChangedVelocity) != 0)
652 {
653 Prim.ForceVelocity = m_knownVelocity;
654 PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, VehicleVelocity);
655 }
656
657 if ((m_knownChanged & m_knownChangedForce) != 0)
658 Prim.AddForce((Vector3)m_knownForce, false, true);
659
660 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
661 {
662 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
663 // Fake out Bullet by making it think the velocity is the same as last time.
664 PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
665 }
666
667 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
668 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true);
669
670 // If we set one of the values (ie, the physics engine didn't do it) we must force
671 // an UpdateProperties event to send the changes up to the simulator.
672 PhysicsScene.PE.PushUpdate(Prim.PhysBody);
673 }
674 m_knownChanged = 0;
675 }
676
677 // Since the computation of terrain height can be a little involved, this routine
678 // is used to fetch the height only once for each vehicle simulation step.
679 private float GetTerrainHeight(Vector3 pos)
680 {
681 if ((m_knownHas & m_knownChangedTerrainHeight) == 0)
682 {
683 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
684 m_knownHas |= m_knownChangedTerrainHeight;
685 }
686 return m_knownTerrainHeight;
687 }
688
689 // Since the computation of water level can be a little involved, this routine
690 // is used ot fetch the level only once for each vehicle simulation step.
691 private float GetWaterLevel(Vector3 pos)
692 {
693 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
694 {
695 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
696 m_knownHas |= m_knownChangedWaterLevel;
697 }
698 return (float)m_knownWaterLevel;
699 }
700
701 private Vector3 VehiclePosition
702 {
703 get
704 {
705 if ((m_knownHas & m_knownChangedPosition) == 0)
706 {
707 m_knownPosition = Prim.ForcePosition;
708 m_knownHas |= m_knownChangedPosition;
709 }
710 return m_knownPosition;
711 }
712 set
713 {
714 m_knownPosition = value;
715 m_knownChanged |= m_knownChangedPosition;
716 m_knownHas |= m_knownChangedPosition;
717 }
718 }
719
720 private Quaternion VehicleOrientation
721 {
722 get
723 {
724 if ((m_knownHas & m_knownChangedOrientation) == 0)
725 {
726 m_knownOrientation = Prim.ForceOrientation;
727 m_knownHas |= m_knownChangedOrientation;
728 }
729 return m_knownOrientation;
730 }
731 set
732 {
733 m_knownOrientation = value;
734 m_knownChanged |= m_knownChangedOrientation;
735 m_knownHas |= m_knownChangedOrientation;
736 }
737 }
738
739 private Vector3 VehicleVelocity
740 {
741 get
742 {
743 if ((m_knownHas & m_knownChangedVelocity) == 0)
744 {
745 m_knownVelocity = Prim.ForceVelocity;
746 m_knownHas |= m_knownChangedVelocity;
747 }
748 return (Vector3)m_knownVelocity;
749 }
750 set
751 {
752 m_knownVelocity = value;
753 m_knownChanged |= m_knownChangedVelocity;
754 m_knownHas |= m_knownChangedVelocity;
755 }
756 }
757
758 private void VehicleAddForce(Vector3 aForce)
759 {
760 if ((m_knownHas & m_knownChangedForce) == 0)
761 {
762 m_knownForce = Vector3.Zero;
763 }
764 m_knownForce += aForce;
765 m_knownChanged |= m_knownChangedForce;
766 m_knownHas |= m_knownChangedForce;
767 }
768
769 private Vector3 VehicleRotationalVelocity
770 {
771 get
772 {
773 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
774 {
775 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
776 m_knownHas |= m_knownChangedRotationalVelocity;
777 }
778 return (Vector3)m_knownRotationalVelocity;
779 }
780 set
781 {
782 m_knownRotationalVelocity = value;
783 m_knownChanged |= m_knownChangedRotationalVelocity;
784 m_knownHas |= m_knownChangedRotationalVelocity;
785 }
786 }
787 private void VehicleAddAngularForce(Vector3 aForce)
788 {
789 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
790 {
791 m_knownRotationalForce = Vector3.Zero;
792 }
793 m_knownRotationalForce += aForce;
794 m_knownChanged |= m_knownChangedRotationalForce;
795 m_knownHas |= m_knownChangedRotationalForce;
796 }
797 // Vehicle relative forward velocity
798 private Vector3 VehicleForwardVelocity
799 {
800 get
801 {
802 if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
803 {
804 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
805 m_knownHas |= m_knownChangedForwardVelocity;
806 }
807 return m_knownForwardVelocity;
808 }
809 }
810 private float VehicleForwardSpeed
811 {
812 get
813 {
814 return VehicleForwardVelocity.X;
815 }
816 }
817
818 #endregion // Known vehicle value functions
819
820 // One step of the vehicle properties for the next 'pTimestep' seconds.
821 internal void Step(float pTimestep)
822 {
823 if (!IsActive) return;
824
825 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
826 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
827
828 ForgetKnownVehicleProperties();
829
830 MoveLinear(pTimestep);
831 MoveAngular(pTimestep);
832
833 LimitRotation(pTimestep);
834
835 // remember the position so next step we can limit absolute movement effects
836 m_lastPositionVector = VehiclePosition;
837
838 // If we forced the changing of some vehicle parameters, update the values and
839 // for the physics engine to note the changes so an UpdateProperties event will happen.
840 PushKnownChanged();
841
842 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
843 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
844
845 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
846 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity);
847 }
848
849 // Apply the effect of the linear motor and other linear motions (like hover and float).
850 private void MoveLinear(float pTimestep)
851 {
852 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
853
854 // The movement computed in the linear motor is relative to the vehicle
855 // coordinates. Rotate the movement to world coordinates.
856 linearMotorContribution *= VehicleOrientation;
857
858 // ==================================================================
859 // Buoyancy: force to overcome gravity.
860 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
861 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
862 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
863
864 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
865
866 Vector3 hoverContribution = ComputeLinearHover(pTimestep);
867
868 ComputeLinearBlockingEndPoint(pTimestep);
869
870 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep);
871
872 // ==================================================================
873 Vector3 newVelocity = linearMotorContribution
874 + terrainHeightContribution
875 + hoverContribution
876 + limitMotorUpContribution;
877
878 Vector3 newForce = buoyancyContribution;
879
880 // If not changing some axis, reduce out velocity
881 if ((m_flags & (VehicleFlag.NO_X)) != 0)
882 newVelocity.X = 0;
883 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
884 newVelocity.Y = 0;
885 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
886 newVelocity.Z = 0;
887
888 // ==================================================================
889 // Clamp high or low velocities
890 float newVelocityLengthSq = newVelocity.LengthSquared();
891 if (newVelocityLengthSq > 1000f)
892 {
893 newVelocity /= newVelocity.Length();
894 newVelocity *= 1000f;
895 }
896 else if (newVelocityLengthSq < 0.001f)
897 newVelocity = Vector3.Zero;
898
899 // ==================================================================
900 // Stuff new linear velocity into the vehicle.
901 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us.
902 VehicleVelocity = newVelocity;
903
904 // Other linear forces are applied as forces.
905 Vector3 totalDownForce = newForce * m_vehicleMass;
906 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
907 {
908 VehicleAddForce(totalDownForce);
909 }
910
911 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}",
912 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding);
913 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
914 Prim.LocalID,
915 linearMotorContribution, terrainHeightContribution, hoverContribution,
916 limitMotorUpContribution, buoyancyContribution
917 );
918
919 } // end MoveLinear()
920
921 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep)
922 {
923 Vector3 ret = Vector3.Zero;
924 // If below the terrain, move us above the ground a little.
925 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
926 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
927 {
928 // TODO: correct position by applying force rather than forcing position.
929 Vector3 newPosition = VehiclePosition;
930 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
931 VehiclePosition = newPosition;
932 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
933 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
934 }
935 return ret;
936 }
937
938 public Vector3 ComputeLinearHover(float pTimestep)
939 {
940 Vector3 ret = Vector3.Zero;
941
942 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
943 // m_VhoverTimescale: time to achieve height
944 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
945 {
946 // We should hover, get the target height
947 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
948 {
949 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
950 }
951 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
952 {
953 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
954 }
955 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
956 {
957 m_VhoverTargetHeight = m_VhoverHeight;
958 }
959
960 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
961 {
962 // If body is already heigher, use its height as target height
963 if (VehiclePosition.Z > m_VhoverTargetHeight)
964 m_VhoverTargetHeight = VehiclePosition.Z;
965 }
966
967 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
968 {
969 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
970 {
971 Vector3 pos = VehiclePosition;
972 pos.Z = m_VhoverTargetHeight;
973 VehiclePosition = pos;
974 }
975 }
976 else
977 {
978 // Error is positive if below the target and negative if above.
979 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z;
980 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
981
982 // TODO: implement m_VhoverEfficiency correctly
983 if (Math.Abs(verticalError) > m_VhoverEfficiency)
984 {
985 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
986 }
987 }
988
989 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}",
990 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight);
991 }
992
993 return ret;
994 }
995
996 public bool ComputeLinearBlockingEndPoint(float pTimestep)
997 {
998 bool changed = false;
999
1000 Vector3 pos = VehiclePosition;
1001 Vector3 posChange = pos - m_lastPositionVector;
1002 if (m_BlockingEndPoint != Vector3.Zero)
1003 {
1004 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
1005 {
1006 pos.X -= posChange.X + 1;
1007 changed = true;
1008 }
1009 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
1010 {
1011 pos.Y -= posChange.Y + 1;
1012 changed = true;
1013 }
1014 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
1015 {
1016 pos.Z -= posChange.Z + 1;
1017 changed = true;
1018 }
1019 if (pos.X <= 0)
1020 {
1021 pos.X += posChange.X + 1;
1022 changed = true;
1023 }
1024 if (pos.Y <= 0)
1025 {
1026 pos.Y += posChange.Y + 1;
1027 changed = true;
1028 }
1029 if (changed)
1030 {
1031 VehiclePosition = pos;
1032 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1033 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
1034 }
1035 }
1036 return changed;
1037 }
1038
1039 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1040 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
1041 // used with conjunction with banking: the strength of the banking will decay when the
1042 // vehicle no longer experiences collisions. The decay timescale is the same as
1043 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1044 // when they are in mid jump.
1045 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1046 // This is just using the ground and a general collision check. Should really be using
1047 // a downward raycast to find what is below.
1048 public Vector3 ComputeLinearMotorUp(float pTimestep)
1049 {
1050 Vector3 ret = Vector3.Zero;
1051 float distanceAboveGround = 0f;
1052
1053 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1054 {
1055 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1056 distanceAboveGround = VehiclePosition.Z - targetHeight;
1057 // Not colliding if the vehicle is off the ground
1058 if (!Prim.IsColliding)
1059 {
1060 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1061 ret = new Vector3(0, 0, -distanceAboveGround);
1062 }
1063 // TODO: this calculation is wrong. From the description at
1064 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1065 // has a decay factor. This says this force should
1066 // be computed with a motor.
1067 // TODO: add interaction with banking.
1068 }
1069 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1070 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
1071 return ret;
1072 }
1073
1074 // =======================================================================
1075 // =======================================================================
1076 // Apply the effect of the angular motor.
1077 // The 'contribution' is how much angular correction velocity each function wants.
1078 // All the contributions are added together and the resulting velocity is
1079 // set directly on the vehicle.
1080 private void MoveAngular(float pTimestep)
1081 {
1082 // The user wants this many radians per second angular change?
1083 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
1084
1085 // ==================================================================
1086 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1087 // This flag prevents linear deflection parallel to world z-axis. This is useful
1088 // for preventing ground vehicles with large linear deflection, like bumper cars,
1089 // from climbing their linear deflection into the sky.
1090 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1091 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1092 {
1093 angularMotorContribution.X = 0f;
1094 angularMotorContribution.Y = 0f;
1095 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
1096 }
1097
1098 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
1099
1100 Vector3 deflectionContribution = ComputeAngularDeflection();
1101
1102 Vector3 bankingContribution = ComputeAngularBanking();
1103
1104 // ==================================================================
1105 m_lastVertAttractor = verticalAttractionContribution;
1106
1107 m_lastAngularVelocity = angularMotorContribution
1108 + verticalAttractionContribution
1109 + deflectionContribution
1110 + bankingContribution;
1111
1112 // ==================================================================
1113 // Apply the correction velocity.
1114 // TODO: Should this be applied as an angular force (torque)?
1115 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1116 {
1117 VehicleRotationalVelocity = m_lastAngularVelocity;
1118
1119 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}",
1120 Prim.LocalID,
1121 angularMotorContribution, verticalAttractionContribution,
1122 bankingContribution, deflectionContribution,
1123 m_lastAngularVelocity
1124 );
1125 }
1126 else
1127 {
1128 // The vehicle is not adding anything angular wise.
1129 VehicleRotationalVelocity = Vector3.Zero;
1130 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
1131 }
1132
1133 // ==================================================================
1134 //Offset section
1135 if (m_linearMotorOffset != Vector3.Zero)
1136 {
1137 //Offset of linear velocity doesn't change the linear velocity,
1138 // but causes a torque to be applied, for example...
1139 //
1140 // IIIII >>> IIIII
1141 // IIIII >>> IIIII
1142 // IIIII >>> IIIII
1143 // ^
1144 // | Applying a force at the arrow will cause the object to move forward, but also rotate
1145 //
1146 //
1147 // The torque created is the linear velocity crossed with the offset
1148
1149 // TODO: this computation should be in the linear section
1150 // because that is where we know the impulse being applied.
1151 Vector3 torqueFromOffset = Vector3.Zero;
1152 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
1153 if (float.IsNaN(torqueFromOffset.X))
1154 torqueFromOffset.X = 0;
1155 if (float.IsNaN(torqueFromOffset.Y))
1156 torqueFromOffset.Y = 0;
1157 if (float.IsNaN(torqueFromOffset.Z))
1158 torqueFromOffset.Z = 0;
1159
1160 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1161 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1162 }
1163
1164 }
1165 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1166 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1167 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1168 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1169 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1170 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1171 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1172 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1173 public Vector3 ComputeAngularVerticalAttraction()
1174 {
1175 Vector3 ret = Vector3.Zero;
1176
1177 // If vertical attaction timescale is reasonable
1178 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1179 {
1180 // Take a vector pointing up and convert it from world to vehicle relative coords.
1181 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1182
1183 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1184 // is now:
1185 // leaning to one side: rotated around the X axis with the Y value going
1186 // from zero (nearly straight up) to one (completely to the side)) or
1187 // leaning front-to-back: rotated around the Y axis with the value of X being between
1188 // zero and one.
1189 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1190
1191 // Y error means needed rotation around X axis and visa versa.
1192 // Since the error goes from zero to one, the asin is the corresponding angle.
1193 ret.X = (float)Math.Asin(verticalError.Y);
1194 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1195 ret.Y = -(float)Math.Asin(verticalError.X);
1196
1197 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1198 if (verticalError.Z < 0f)
1199 {
1200 ret.X += PIOverFour;
1201 ret.Y += PIOverFour;
1202 }
1203
1204 // 'ret' is now the necessary velocity to correct tilt in one second.
1205 // Correction happens over a number of seconds.
1206 Vector3 unscaledContrib = ret;
1207 ret /= m_verticalAttractionTimescale;
1208
1209 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1210 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
1211 }
1212 return ret;
1213 }
1214
1215 // Return the angular correction to correct the direction the vehicle is pointing to be
1216 // the direction is should want to be pointing.
1217 // The vehicle is moving in some direction and correct its orientation to it is pointing
1218 // in that direction.
1219 // TODO: implement reference frame.
1220 public Vector3 ComputeAngularDeflection()
1221 {
1222 Vector3 ret = Vector3.Zero;
1223 return ret; // DEBUG DEBUG DEBUG
1224 // Disable angular deflection for the moment.
1225 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1226 // approximately the same X or Y correction. When added together (when contributions are combined)
1227 // this creates an over-correction and then wabbling as the target is overshot.
1228 // TODO: rethink how the different correction computations inter-relate.
1229
1230 if (m_angularDeflectionEfficiency != 0)
1231 {
1232 // The direction the vehicle is moving
1233 Vector3 movingDirection = VehicleVelocity;
1234 movingDirection.Normalize();
1235
1236 // The direction the vehicle is pointing
1237 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1238 pointingDirection.Normalize();
1239
1240 // The difference between what is and what should be.
1241 Vector3 deflectionError = movingDirection - pointingDirection;
1242
1243 // Don't try to correct very large errors (not our job)
1244 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1245 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1246 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1247
1248 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1249
1250 // Scale the correction by recovery timescale and efficiency
1251 ret = (-deflectionError) * m_angularDeflectionEfficiency;
1252 ret /= m_angularDeflectionTimescale;
1253
1254 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1255 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
1256 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1257 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1258 }
1259 return ret;
1260 }
1261
1262 // Return an angular change to rotate the vehicle around the Z axis when the vehicle
1263 // is tipped around the X axis.
1264 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1265 // The vertical attractor feature must be enabled in order for the banking behavior to
1266 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1267 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1268 // of the yaw effect will be proportional to the
1269 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1270 // velocity along its preferred axis of motion.
1271 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1272 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1273 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1274 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1275 // Negating the banking coefficient will make it so that the vehicle leans to the
1276 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1277 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1278 // banking vehicles do what you want rather than what the laws of physics allow.
1279 // For example, consider a real motorcycle...it must be moving forward in order for
1280 // it to turn while banking, however video-game motorcycles are often configured
1281 // to turn in place when at a dead stop--because they are often easier to control
1282 // that way using the limited interface of the keyboard or game controller. The
1283 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1284 // banking by functioning as a slider between a banking that is correspondingly
1285 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1286 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1287 // to "dynamic" where the banking is also proportional to its velocity along its
1288 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1289 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1290 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1291 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1292 // make a sluggish vehicle by giving it a timescale of several seconds.
1293 public Vector3 ComputeAngularBanking()
1294 {
1295 Vector3 ret = Vector3.Zero;
1296
1297 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1298 {
1299 // This works by rotating a unit vector to the orientation of the vehicle. The
1300 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1301 // up to one for full over).
1302 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1303
1304 // Figure out the yaw value for this much roll.
1305 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency;
1306 // Keep the sign
1307 if (rollComponents.Y < 0f)
1308 turnComponent = -turnComponent;
1309
1310 // TODO: there must be a better computation of the banking force.
1311 float bankingTurnForce = turnComponent;
1312
1313 // actual error = static turn error + dynamic turn error
1314 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed;
1315 // TODO: the banking effect should not go to infinity but what to limit it to?
1316 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f);
1317
1318 // Build the force vector to change rotation from what it is to what it should be
1319 ret.Z = -mixedBankingError;
1320
1321 // Don't do it all at once.
1322 ret /= m_bankingTimescale;
1323
1324 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}",
1325 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret);
1326 }
1327 return ret;
1328 }
1329
1330 // This is from previous instantiations of XXXDynamics.cs.
1331 // Applies roll reference frame.
1332 // TODO: is this the right way to separate the code to do this operation?
1333 // Should this be in MoveAngular()?
1334 internal void LimitRotation(float timestep)
1335 {
1336 Quaternion rotq = VehicleOrientation;
1337 Quaternion m_rot = rotq;
1338 if (m_RollreferenceFrame != Quaternion.Identity)
1339 {
1340 if (rotq.X >= m_RollreferenceFrame.X)
1341 {
1342 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
1343 }
1344 if (rotq.Y >= m_RollreferenceFrame.Y)
1345 {
1346 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
1347 }
1348 if (rotq.X <= -m_RollreferenceFrame.X)
1349 {
1350 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
1351 }
1352 if (rotq.Y <= -m_RollreferenceFrame.Y)
1353 {
1354 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
1355 }
1356 }
1357 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
1358 {
1359 m_rot.X = 0;
1360 m_rot.Y = 0;
1361 }
1362 if (rotq != m_rot)
1363 {
1364 VehicleOrientation = m_rot;
1365 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1366 }
1367
1368 }
1369
1370 private float ClampInRange(float low, float val, float high)
1371 {
1372 return Math.Max(low, Math.Min(val, high));
1373 // return Utils.Clamp(val, low, high);
1374 }
1375
1376 // Invoke the detailed logger and output something if it's enabled.
1377 private void VDetailLog(string msg, params Object[] args)
1378 {
1379 if (Prim.PhysicsScene.VehicleLoggingEnabled)
1380 Prim.PhysicsScene.DetailLog(msg, args);
1381 }
1382 }
1383}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
deleted file mode 100755
index 756faed..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ /dev/null
@@ -1,329 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36// A BSPrim can get individual information about its linkedness attached
37// to it through an instance of a subclass of LinksetInfo.
38// Each type of linkset will define the information needed for its type.
39public abstract class BSLinksetInfo
40{
41 public virtual void Clear() { }
42}
43
44public abstract class BSLinkset
45{
46 // private static string LogHeader = "[BULLETSIM LINKSET]";
47
48 public enum LinksetImplementation
49 {
50 Constraint = 0, // linkset tied together with constraints
51 Compound = 1, // linkset tied together as a compound object
52 Manual = 2 // linkset tied together manually (code moves all the pieces)
53 }
54 // Create the correct type of linkset for this child
55 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
56 {
57 BSLinkset ret = null;
58
59 switch ((int)BSParam.LinksetImplementation)
60 {
61 case (int)LinksetImplementation.Constraint:
62 ret = new BSLinksetConstraints(physScene, parent);
63 break;
64 case (int)LinksetImplementation.Compound:
65 ret = new BSLinksetCompound(physScene, parent);
66 break;
67 case (int)LinksetImplementation.Manual:
68 // ret = new BSLinksetManual(physScene, parent);
69 break;
70 default:
71 ret = new BSLinksetCompound(physScene, parent);
72 break;
73 }
74 return ret;
75 }
76
77 public BSPhysObject LinksetRoot { get; protected set; }
78
79 public BSScene PhysicsScene { get; private set; }
80
81 static int m_nextLinksetID = 1;
82 public int LinksetID { get; private set; }
83
84 // The children under the root in this linkset.
85 protected HashSet<BSPhysObject> m_children;
86
87 // We lock the diddling of linkset classes to prevent any badness.
88 // This locks the modification of the instances of this class. Changes
89 // to the physical representation is done via the tainting mechenism.
90 protected object m_linksetActivityLock = new Object();
91
92 // Some linksets have a preferred physical shape.
93 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
94 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
95 {
96 return BSPhysicsShapeType.SHAPE_UNKNOWN;
97 }
98
99 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
100 public float LinksetMass { get; protected set; }
101
102 public virtual bool LinksetIsColliding { get { return false; } }
103
104 public OMV.Vector3 CenterOfMass
105 {
106 get { return ComputeLinksetCenterOfMass(); }
107 }
108
109 public OMV.Vector3 GeometricCenter
110 {
111 get { return ComputeLinksetGeometricCenter(); }
112 }
113
114 protected BSLinkset(BSScene scene, BSPhysObject parent)
115 {
116 // A simple linkset of one (no children)
117 LinksetID = m_nextLinksetID++;
118 // We create LOTS of linksets.
119 if (m_nextLinksetID <= 0)
120 m_nextLinksetID = 1;
121 PhysicsScene = scene;
122 LinksetRoot = parent;
123 m_children = new HashSet<BSPhysObject>();
124 LinksetMass = parent.RawMass;
125 Rebuilding = false;
126 }
127
128 // Link to a linkset where the child knows the parent.
129 // Parent changing should not happen so do some sanity checking.
130 // We return the parent's linkset so the child can track its membership.
131 // Called at runtime.
132 public BSLinkset AddMeToLinkset(BSPhysObject child)
133 {
134 lock (m_linksetActivityLock)
135 {
136 // Don't add the root to its own linkset
137 if (!IsRoot(child))
138 AddChildToLinkset(child);
139 LinksetMass = ComputeLinksetMass();
140 }
141 return this;
142 }
143
144 // Remove a child from a linkset.
145 // Returns a new linkset for the child which is a linkset of one (just the
146 // orphened child).
147 // Called at runtime.
148 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
149 {
150 lock (m_linksetActivityLock)
151 {
152 if (IsRoot(child))
153 {
154 // Cannot remove the root from a linkset.
155 return this;
156 }
157 RemoveChildFromLinkset(child);
158 LinksetMass = ComputeLinksetMass();
159 }
160
161 // The child is down to a linkset of just itself
162 return BSLinkset.Factory(PhysicsScene, child);
163 }
164
165 // Return 'true' if the passed object is the root object of this linkset
166 public bool IsRoot(BSPhysObject requestor)
167 {
168 return (requestor.LocalID == LinksetRoot.LocalID);
169 }
170
171 public int NumberOfChildren { get { return m_children.Count; } }
172
173 // Return 'true' if this linkset has any children (more than the root member)
174 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
175
176 // Return 'true' if this child is in this linkset
177 public bool HasChild(BSPhysObject child)
178 {
179 bool ret = false;
180 lock (m_linksetActivityLock)
181 {
182 ret = m_children.Contains(child);
183 /* Safer version but the above should work
184 foreach (BSPhysObject bp in m_children)
185 {
186 if (child.LocalID == bp.LocalID)
187 {
188 ret = true;
189 break;
190 }
191 }
192 */
193 }
194 return ret;
195 }
196
197 // Perform an action on each member of the linkset including root prim.
198 // Depends on the action on whether this should be done at taint time.
199 public delegate bool ForEachMemberAction(BSPhysObject obj);
200 public virtual bool ForEachMember(ForEachMemberAction action)
201 {
202 bool ret = false;
203 lock (m_linksetActivityLock)
204 {
205 action(LinksetRoot);
206 foreach (BSPhysObject po in m_children)
207 {
208 if (action(po))
209 break;
210 }
211 }
212 return ret;
213 }
214
215 // I am the root of a linkset and a new child is being added
216 // Called while LinkActivity is locked.
217 protected abstract void AddChildToLinkset(BSPhysObject child);
218
219 // I am the root of a linkset and one of my children is being removed.
220 // Safe to call even if the child is not really in my linkset.
221 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
222
223 // When physical properties are changed the linkset needs to recalculate
224 // its internal properties.
225 // May be called at runtime or taint-time.
226 public virtual void Refresh(BSPhysObject requestor)
227 {
228 LinksetMass = ComputeLinksetMass();
229 }
230
231 // Flag denoting the linkset is in the process of being rebuilt.
232 // Used to know not the schedule a rebuild in the middle of a rebuild.
233 protected bool Rebuilding { get; set; }
234
235 // The object is going dynamic (physical). Do any setup necessary
236 // for a dynamic linkset.
237 // Only the state of the passed object can be modified. The rest of the linkset
238 // has not yet been fully constructed.
239 // Return 'true' if any properties updated on the passed object.
240 // Called at taint-time!
241 public abstract bool MakeDynamic(BSPhysObject child);
242
243 // The object is going static (non-physical). Do any setup necessary
244 // for a static linkset.
245 // Return 'true' if any properties updated on the passed object.
246 // Called at taint-time!
247 public abstract bool MakeStatic(BSPhysObject child);
248
249 // Called when a parameter update comes from the physics engine for any object
250 // of the linkset is received.
251 // Passed flag is update came from physics engine (true) or the user (false).
252 // Called at taint-time!!
253 public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
254
255 // Routine used when rebuilding the body of the root of the linkset
256 // Destroy all the constraints have have been made to root.
257 // This is called when the root body is changing.
258 // Returns 'true' of something was actually removed and would need restoring
259 // Called at taint-time!!
260 public abstract bool RemoveBodyDependencies(BSPrim child);
261
262 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
263 // this routine will restore the removed constraints.
264 // Called at taint-time!!
265 public abstract void RestoreBodyDependencies(BSPrim child);
266
267 // ================================================================
268 protected virtual float ComputeLinksetMass()
269 {
270 float mass = LinksetRoot.RawMass;
271 if (HasAnyChildren)
272 {
273 lock (m_linksetActivityLock)
274 {
275 foreach (BSPhysObject bp in m_children)
276 {
277 mass += bp.RawMass;
278 }
279 }
280 }
281 return mass;
282 }
283
284 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
285 {
286 OMV.Vector3 com;
287 lock (m_linksetActivityLock)
288 {
289 com = LinksetRoot.Position * LinksetRoot.RawMass;
290 float totalMass = LinksetRoot.RawMass;
291
292 foreach (BSPhysObject bp in m_children)
293 {
294 com += bp.Position * bp.RawMass;
295 totalMass += bp.RawMass;
296 }
297 if (totalMass != 0f)
298 com /= totalMass;
299 }
300
301 return com;
302 }
303
304 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
305 {
306 OMV.Vector3 com;
307 lock (m_linksetActivityLock)
308 {
309 com = LinksetRoot.Position;
310
311 foreach (BSPhysObject bp in m_children)
312 {
313 com += bp.Position * bp.RawMass;
314 }
315 com /= (m_children.Count + 1);
316 }
317
318 return com;
319 }
320
321 // Invoke the detailed logger and output something if it's enabled.
322 protected void DetailLog(string msg, params Object[] args)
323 {
324 if (PhysicsScene.PhysicsLogging.Enabled)
325 PhysicsScene.DetailLog(msg, args);
326 }
327
328}
329}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
deleted file mode 100755
index bd03d31..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ /dev/null
@@ -1,392 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37
38// When a child is linked, the relationship position of the child to the parent
39// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{
43 public OMV.Vector3 OffsetPos;
44 public OMV.Quaternion OffsetRot;
45 public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
46 {
47 OffsetPos = p;
48 OffsetRot = r;
49 }
50 public override void Clear()
51 {
52 OffsetPos = OMV.Vector3.Zero;
53 OffsetRot = OMV.Quaternion.Identity;
54 }
55 public override string ToString()
56 {
57 StringBuilder buff = new StringBuilder();
58 buff.Append("<p=");
59 buff.Append(OffsetPos.ToString());
60 buff.Append(",r=");
61 buff.Append(OffsetRot.ToString());
62 buff.Append(">");
63 return buff.ToString();
64 }
65};
66
67public sealed class BSLinksetCompound : BSLinkset
68{
69 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
70
71 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
72 {
73 }
74
75 // For compound implimented linksets, if there are children, use compound shape for the root.
76 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
77 {
78 // Returning 'unknown' means we don't have a preference.
79 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
80 if (IsRoot(requestor) && HasAnyChildren)
81 {
82 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
83 }
84 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
85 return ret;
86 }
87
88 // When physical properties are changed the linkset needs to recalculate
89 // its internal properties.
90 public override void Refresh(BSPhysObject requestor)
91 {
92 base.Refresh(requestor);
93
94 // Something changed so do the rebuilding thing
95 // ScheduleRebuild();
96 }
97
98 // Schedule a refresh to happen after all the other taint processing.
99 private void ScheduleRebuild(BSPhysObject requestor)
100 {
101 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}",
102 requestor.LocalID, Rebuilding, HasAnyChildren);
103 // When rebuilding, it is possible to set properties that would normally require a rebuild.
104 // If already rebuilding, don't request another rebuild.
105 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
106 if (!Rebuilding && HasAnyChildren)
107 {
108 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
109 {
110 if (HasAnyChildren)
111 RecomputeLinksetCompound();
112 });
113 }
114 }
115
116 // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
117 // Only the state of the passed object can be modified. The rest of the linkset
118 // has not yet been fully constructed.
119 // Return 'true' if any properties updated on the passed object.
120 // Called at taint-time!
121 public override bool MakeDynamic(BSPhysObject child)
122 {
123 bool ret = false;
124 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
125 if (IsRoot(child))
126 {
127 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
128 ScheduleRebuild(LinksetRoot);
129 }
130 else
131 {
132 // The origional prims are removed from the world as the shape of the root compound
133 // shape takes over.
134 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
135 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
136 // We don't want collisions from the old linkset children.
137 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
138
139 child.PhysBody.collisionType = CollisionType.LinksetChild;
140
141 ret = true;
142 }
143 return ret;
144 }
145
146 // The object is going static (non-physical). Do any setup necessary for a static linkset.
147 // Return 'true' if any properties updated on the passed object.
148 // This doesn't normally happen -- OpenSim removes the objects from the physical
149 // world if it is a static linkset.
150 // Called at taint-time!
151 public override bool MakeStatic(BSPhysObject child)
152 {
153 bool ret = false;
154 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
155 if (IsRoot(child))
156 {
157 ScheduleRebuild(LinksetRoot);
158 }
159 else
160 {
161 // The non-physical children can come back to life.
162 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
163
164 child.PhysBody.collisionType = CollisionType.LinksetChild;
165
166 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
167 PhysicsScene.PE.Activate(child.PhysBody, false);
168 ret = true;
169 }
170 return ret;
171 }
172
173 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
174 {
175 // The user moving a child around requires the rebuilding of the linkset compound shape
176 // One problem is this happens when a border is crossed -- the simulator implementation
177 // is to store the position into the group which causes the move of the object
178 // but it also means all the child positions get updated.
179 // What would cause an unnecessary rebuild so we make sure the linkset is in a
180 // region before bothering to do a rebuild.
181 if (!IsRoot(updated)
182 && !physicalUpdate
183 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
184 {
185 updated.LinksetInfo = null;
186 ScheduleRebuild(updated);
187 }
188 }
189
190 // Routine called when rebuilding the body of some member of the linkset.
191 // Since we don't keep in world relationships, do nothing unless it's a child changing.
192 // Returns 'true' of something was actually removed and would need restoring
193 // Called at taint-time!!
194 public override bool RemoveBodyDependencies(BSPrim child)
195 {
196 bool ret = false;
197
198 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
199 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child));
200
201 if (!IsRoot(child))
202 {
203 // Because it is a convenient time, recompute child world position and rotation based on
204 // its position in the linkset.
205 RecomputeChildWorldPosition(child, true);
206 }
207
208 // Cannot schedule a refresh/rebuild here because this routine is called when
209 // the linkset is being rebuilt.
210 // InternalRefresh(LinksetRoot);
211
212 return ret;
213 }
214
215 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
216 // this routine will restore the removed constraints.
217 // Called at taint-time!!
218 public override void RestoreBodyDependencies(BSPrim child)
219 {
220 }
221
222 // When the linkset is built, the child shape is added to the compound shape relative to the
223 // root shape. The linkset then moves around but this does not move the actual child
224 // prim. The child prim's location must be recomputed based on the location of the root shape.
225 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
226 {
227 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
228 if (lci != null)
229 {
230 if (inTaintTime)
231 {
232 OMV.Vector3 oldPos = child.RawPosition;
233 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
234 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
235 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
236 child.LocalID, oldPos, lci, child.RawPosition);
237 }
238 else
239 {
240 // TaintedObject is not used here so the raw position is set now and not at taint-time.
241 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
242 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
243 }
244 }
245 else
246 {
247 // This happens when children have been added to the linkset but the linkset
248 // has not been constructed yet. So like, at taint time, adding children to a linkset
249 // and then changing properties of the children (makePhysical, for instance)
250 // but the post-print action of actually rebuilding the linkset has not yet happened.
251 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
252 // LogHeader, child.LocalID);
253 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
254 }
255 }
256
257 // ================================================================
258
259 // Add a new child to the linkset.
260 // Called while LinkActivity is locked.
261 protected override void AddChildToLinkset(BSPhysObject child)
262 {
263 if (!HasChild(child))
264 {
265 m_children.Add(child);
266
267 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
268
269 // Rebuild the compound shape with the new child shape included
270 ScheduleRebuild(child);
271 }
272 return;
273 }
274
275 // Remove the specified child from the linkset.
276 // Safe to call even if the child is not really in the linkset.
277 protected override void RemoveChildFromLinkset(BSPhysObject child)
278 {
279 if (m_children.Remove(child))
280 {
281 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
282 child.LocalID,
283 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
284 child.LocalID, child.PhysBody.AddrString);
285
286 // Cause the child's body to be rebuilt and thus restored to normal operation
287 RecomputeChildWorldPosition(child, false);
288 child.ForceBodyShapeRebuild(false);
289
290 if (!HasAnyChildren)
291 {
292 // The linkset is now empty. The root needs rebuilding.
293 LinksetRoot.ForceBodyShapeRebuild(false);
294 }
295 else
296 {
297 // Rebuild the compound shape with the child removed
298 ScheduleRebuild(child);
299 }
300 }
301 return;
302 }
303
304 // Called before the simulation step to make sure the compound based linkset
305 // is all initialized.
306 // Constraint linksets are rebuilt every time.
307 // Note that this works for rebuilding just the root after a linkset is taken apart.
308 // Called at taint time!!
309 private void RecomputeLinksetCompound()
310 {
311 try
312 {
313 // Suppress rebuilding while rebuilding
314 Rebuilding = true;
315
316 // Cause the root shape to be rebuilt as a compound object with just the root in it
317 LinksetRoot.ForceBodyShapeRebuild(true);
318
319 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
320 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
321
322 // Add a shape for each of the other children in the linkset
323 ForEachMember(delegate(BSPhysObject cPrim)
324 {
325 if (!IsRoot(cPrim))
326 {
327 // Compute the displacement of the child from the root of the linkset.
328 // This info is saved in the child prim so the relationship does not
329 // change over time and the new child position can be computed
330 // when the linkset is being disassembled (the linkset may have moved).
331 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
332 if (lci == null)
333 {
334 // Each child position and rotation is given relative to the root.
335 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
336 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
337 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
338
339 // Save relative position for recomputing child's world position after moving linkset.
340 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
341 cPrim.LinksetInfo = lci;
342 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
343 }
344
345 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
346 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
347
348 if (cPrim.PhysShape.isNativeShape)
349 {
350 // A native shape is turning into a hull collision shape because native
351 // shapes are not shared so we have to hullify it so it will be tracked
352 // and freed at the correct time. This also solves the scaling problem
353 // (native shapes scaled but hull/meshes are assumed to not be).
354 // TODO: decide of the native shape can just be used in the compound shape.
355 // Use call to CreateGeomNonSpecial().
356 BulletShape saveShape = cPrim.PhysShape;
357 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
358 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
359 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
360 BulletShape newShape = cPrim.PhysShape;
361 cPrim.PhysShape = saveShape;
362 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetPos, lci.OffsetRot);
363 }
364 else
365 {
366 // For the shared shapes (meshes and hulls), just use the shape in the child.
367 // The reference count added here will be decremented when the compound shape
368 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
369 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
370 {
371 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
372 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
373 }
374 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
375 }
376 }
377 return false; // 'false' says to move onto the next child in the list
378 });
379
380 // With all of the linkset packed into the root prim, it has the mass of everyone.
381 LinksetMass = ComputeLinksetMass();
382 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
383 }
384 finally
385 {
386 Rebuilding = false;
387 }
388
389 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
390 }
391}
392} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
deleted file mode 100755
index d0b2a56..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ /dev/null
@@ -1,312 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public sealed class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 {
41 }
42
43 // When physical properties are changed the linkset needs to recalculate
44 // its internal properties.
45 // This is queued in the 'post taint' queue so the
46 // refresh will happen once after all the other taints are applied.
47 public override void Refresh(BSPhysObject requestor)
48 {
49 base.Refresh(requestor);
50
51 if (HasAnyChildren && IsRoot(requestor))
52 {
53 // Queue to happen after all the other taint processing
54 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
55 {
56 if (HasAnyChildren && IsRoot(requestor))
57 RecomputeLinksetConstraints();
58 });
59 }
60 }
61
62 // The object is going dynamic (physical). Do any setup necessary
63 // for a dynamic linkset.
64 // Only the state of the passed object can be modified. The rest of the linkset
65 // has not yet been fully constructed.
66 // Return 'true' if any properties updated on the passed object.
67 // Called at taint-time!
68 public override bool MakeDynamic(BSPhysObject child)
69 {
70 // What is done for each object in BSPrim is what we want.
71 return false;
72 }
73
74 // The object is going static (non-physical). Do any setup necessary for a static linkset.
75 // Return 'true' if any properties updated on the passed object.
76 // This doesn't normally happen -- OpenSim removes the objects from the physical
77 // world if it is a static linkset.
78 // Called at taint-time!
79 public override bool MakeStatic(BSPhysObject child)
80 {
81 // What is done for each object in BSPrim is what we want.
82 return false;
83 }
84
85 // Called at taint-time!!
86 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
87 {
88 // Nothing to do for constraints on property updates
89 }
90
91 // Routine called when rebuilding the body of some member of the linkset.
92 // Destroy all the constraints have have been made to root and set
93 // up to rebuild the constraints before the next simulation step.
94 // Returns 'true' of something was actually removed and would need restoring
95 // Called at taint-time!!
96 public override bool RemoveBodyDependencies(BSPrim child)
97 {
98 bool ret = false;
99
100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
102
103 lock (m_linksetActivityLock)
104 {
105 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
106 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
107 // Cause the constraints, et al to be rebuilt before the next simulation step.
108 Refresh(LinksetRoot);
109 }
110 return ret;
111 }
112
113 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
114 // this routine will restore the removed constraints.
115 // Called at taint-time!!
116 public override void RestoreBodyDependencies(BSPrim child)
117 {
118 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
119 }
120
121 // ================================================================
122
123 // Add a new child to the linkset.
124 // Called while LinkActivity is locked.
125 protected override void AddChildToLinkset(BSPhysObject child)
126 {
127 if (!HasChild(child))
128 {
129 m_children.Add(child);
130
131 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
132
133 // Cause constraints and assorted properties to be recomputed before the next simulation step.
134 Refresh(LinksetRoot);
135 }
136 return;
137 }
138
139 // Remove the specified child from the linkset.
140 // Safe to call even if the child is not really in my linkset.
141 protected override void RemoveChildFromLinkset(BSPhysObject child)
142 {
143 if (m_children.Remove(child))
144 {
145 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
146 BSPhysObject childx = child;
147
148 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
149 childx.LocalID,
150 rootx.LocalID, rootx.PhysBody.AddrString,
151 childx.LocalID, childx.PhysBody.AddrString);
152
153 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
154 {
155 PhysicallyUnlinkAChildFromRoot(rootx, childx);
156 });
157 // See that the linkset parameters are recomputed at the end of the taint time.
158 Refresh(LinksetRoot);
159 }
160 else
161 {
162 // Non-fatal occurance.
163 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
164 }
165 return;
166 }
167
168 // Create a constraint between me (root of linkset) and the passed prim (the child).
169 // Called at taint time!
170 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
171 {
172 // Don't build the constraint when asked. Put it off until just before the simulation step.
173 Refresh(rootPrim);
174 }
175
176 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
177 {
178 // Zero motion for children so they don't interpolate
179 childPrim.ZeroMotion(true);
180
181 // Relative position normalized to the root prim
182 // Essentually a vector pointing from center of rootPrim to center of childPrim
183 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
184
185 // real world coordinate of midpoint between the two objects
186 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
187
188 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
189 rootPrim.LocalID,
190 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
191 childPrim.LocalID, childPrim.PhysBody.AddrString,
192 rootPrim.Position, childPrim.Position, midPoint);
193
194 // create a constraint that allows no freedom of movement between the two objects
195 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
196
197 BSConstraint6Dof constrain = new BSConstraint6Dof(
198 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
199 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
200
201 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
202 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
203 * of the objects.
204 * Code left for future programmers.
205 // ==================================================================================
206 // relative position normalized to the root prim
207 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
208 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
209
210 // relative rotation of the child to the parent
211 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
212 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
213
214 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
215 BS6DofConstraint constrain = new BS6DofConstraint(
216 PhysicsScene.World, rootPrim.Body, childPrim.Body,
217 OMV.Vector3.Zero,
218 OMV.Quaternion.Inverse(rootPrim.Orientation),
219 OMV.Vector3.Zero,
220 OMV.Quaternion.Inverse(childPrim.Orientation),
221 true,
222 true
223 );
224 // ==================================================================================
225 */
226
227 PhysicsScene.Constraints.AddConstraint(constrain);
228
229 // zero linear and angular limits makes the objects unable to move in relation to each other
230 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
231 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
232
233 // tweek the constraint to increase stability
234 constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
235 constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
236 BSParam.LinkConstraintTransMotorMaxVel,
237 BSParam.LinkConstraintTransMotorMaxForce);
238 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
239 if (BSParam.LinkConstraintSolverIterations != 0f)
240 {
241 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
242 }
243 return constrain;
244 }
245
246 // Remove linkage between the linkset root and a particular child
247 // The root and child bodies are passed in because we need to remove the constraint between
248 // the bodies that were present at unlink time.
249 // Called at taint time!
250 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
251 {
252 bool ret = false;
253 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
254 rootPrim.LocalID,
255 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
256 childPrim.LocalID, childPrim.PhysBody.AddrString);
257
258 // Find the constraint for this link and get rid of it from the overall collection and from my list
259 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
260 {
261 // Make the child refresh its location
262 PhysicsScene.PE.PushUpdate(childPrim.PhysBody);
263 ret = true;
264 }
265
266 return ret;
267 }
268
269 // Remove linkage between myself and any possible children I might have.
270 // Returns 'true' of any constraints were destroyed.
271 // Called at taint time!
272 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
273 {
274 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
275
276 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
277 }
278
279 // Call each of the constraints that make up this linkset and recompute the
280 // various transforms and variables. Create constraints of not created yet.
281 // Called before the simulation step to make sure the constraint based linkset
282 // is all initialized.
283 // Called at taint time!!
284 private void RecomputeLinksetConstraints()
285 {
286 float linksetMass = LinksetMass;
287 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
288
289 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
290 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
291
292 foreach (BSPhysObject child in m_children)
293 {
294 // A child in the linkset physically shows the mass of the whole linkset.
295 // This allows Bullet to apply enough force on the child to move the whole linkset.
296 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
297 child.UpdatePhysicalMassProperties(linksetMass, true);
298
299 BSConstraint constrain;
300 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
301 {
302 // If constraint doesn't exist yet, create it.
303 constrain = BuildConstraint(LinksetRoot, child);
304 }
305 constrain.RecomputeConstraintVariables(linksetMass);
306
307 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
308 }
309
310 }
311}
312}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
deleted file mode 100755
index 69ac8cd..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ /dev/null
@@ -1,582 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Region.Physics.Manager;
32
33using OpenMetaverse;
34using Nini.Config;
35
36namespace OpenSim.Region.Physics.BulletSPlugin
37{
38public static class BSParam
39{
40 // Level of Detail values kept as float because that's what the Meshmerizer wants
41 public static float MeshLOD { get; private set; }
42 public static float MeshMegaPrimLOD { get; private set; }
43 public static float MeshMegaPrimThreshold { get; private set; }
44 public static float SculptLOD { get; private set; }
45
46 public static float MinimumObjectMass { get; private set; }
47 public static float MaximumObjectMass { get; private set; }
48
49 public static float LinearDamping { get; private set; }
50 public static float AngularDamping { get; private set; }
51 public static float DeactivationTime { get; private set; }
52 public static float LinearSleepingThreshold { get; private set; }
53 public static float AngularSleepingThreshold { get; private set; }
54 public static float CcdMotionThreshold { get; private set; }
55 public static float CcdSweptSphereRadius { get; private set; }
56 public static float ContactProcessingThreshold { get; private set; }
57
58 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
59 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
60 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
61
62 public static float TerrainImplementation { get; private set; }
63 public static float TerrainFriction { get; private set; }
64 public static float TerrainHitFraction { get; private set; }
65 public static float TerrainRestitution { get; private set; }
66 public static float TerrainCollisionMargin { get; private set; }
67
68 // Avatar parameters
69 public static float AvatarFriction { get; private set; }
70 public static float AvatarStandingFriction { get; private set; }
71 public static float AvatarAlwaysRunFactor { get; private set; }
72 public static float AvatarDensity { get; private set; }
73 public static float AvatarRestitution { get; private set; }
74 public static float AvatarCapsuleWidth { get; private set; }
75 public static float AvatarCapsuleDepth { get; private set; }
76 public static float AvatarCapsuleHeight { get; private set; }
77 public static float AvatarContactProcessingThreshold { get; private set; }
78
79 public static float VehicleAngularDamping { get; private set; }
80
81 public static float LinksetImplementation { get; private set; }
82 public static float LinkConstraintUseFrameOffset { get; private set; }
83 public static float LinkConstraintEnableTransMotor { get; private set; }
84 public static float LinkConstraintTransMotorMaxVel { get; private set; }
85 public static float LinkConstraintTransMotorMaxForce { get; private set; }
86 public static float LinkConstraintERP { get; private set; }
87 public static float LinkConstraintCFM { get; private set; }
88 public static float LinkConstraintSolverIterations { get; private set; }
89
90 public static float PID_D { get; private set; } // derivative
91 public static float PID_P { get; private set; } // proportional
92
93 // Various constants that come from that other virtual world that shall not be named
94 public const float MinGravityZ = -1f;
95 public const float MaxGravityZ = 28f;
96 public const float MinFriction = 0f;
97 public const float MaxFriction = 255f;
98 public const float MinDensity = 0f;
99 public const float MaxDensity = 22587f;
100 public const float MinRestitution = 0f;
101 public const float MaxRestitution = 1f;
102 public const float MaxAddForceMagnitude = 20000f;
103
104 // ===========================================================================
105 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
106 public delegate float ParamGet(BSScene scene);
107 public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
108 public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
109
110 public struct ParameterDefn
111 {
112 public string name; // string name of the parameter
113 public string desc; // a short description of what the parameter means
114 public float defaultValue; // default value if not specified anywhere else
115 public ParamUser userParam; // get the value from the configuration file
116 public ParamGet getter; // return the current value stored for this parameter
117 public ParamSet setter; // set the current value for this parameter
118 public SetOnObject onObject; // set the value on an object in the physical domain
119 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
120 {
121 name = n;
122 desc = d;
123 defaultValue = v;
124 userParam = u;
125 getter = g;
126 setter = s;
127 onObject = null;
128 }
129 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
130 {
131 name = n;
132 desc = d;
133 defaultValue = v;
134 userParam = u;
135 getter = g;
136 setter = s;
137 onObject = o;
138 }
139 }
140
141 // List of all of the externally visible parameters.
142 // For each parameter, this table maps a text name to getter and setters.
143 // To add a new externally referencable/settable parameter, add the paramter storage
144 // location somewhere in the program and make an entry in this table with the
145 // getters and setters.
146 // It is easiest to find an existing definition and copy it.
147 // Parameter values are floats. Booleans are converted to a floating value.
148 //
149 // A ParameterDefn() takes the following parameters:
150 // -- the text name of the parameter. This is used for console input and ini file.
151 // -- a short text description of the parameter. This shows up in the console listing.
152 // -- a default value (float)
153 // -- a delegate for fetching the parameter from the ini file.
154 // Should handle fetching the right type from the ini file and converting it.
155 // -- a delegate for getting the value as a float
156 // -- a delegate for setting the value from a float
157 // -- an optional delegate to update the value in the world. Most often used to
158 // push the new value to an in-world object.
159 //
160 // The single letter parameters for the delegates are:
161 // s = BSScene
162 // o = BSPhysObject
163 // p = string parameter name
164 // l = localID of referenced object
165 // v = value (float)
166 // cf = parameter configuration class (for fetching values from ini file)
167 private static ParameterDefn[] ParameterDefinitions =
168 {
169 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
170 ConfigurationParameters.numericTrue,
171 (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
172 (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
173 (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
174 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
175 ConfigurationParameters.numericFalse,
176 (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
177 (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
178 (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
179 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
180 ConfigurationParameters.numericTrue,
181 (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
182 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
183 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
184
185 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
186 8f,
187 (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
188 (s) => { return MeshLOD; },
189 (s,p,l,v) => { MeshLOD = v; } ),
190 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
191 16f,
192 (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
193 (s) => { return MeshMegaPrimLOD; },
194 (s,p,l,v) => { MeshMegaPrimLOD = v; } ),
195 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
196 10f,
197 (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
198 (s) => { return MeshMegaPrimThreshold; },
199 (s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
200 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
201 32f,
202 (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
203 (s) => { return SculptLOD; },
204 (s,p,l,v) => { SculptLOD = v; } ),
205
206 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
207 10f,
208 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
209 (s) => { return (float)s.m_maxSubSteps; },
210 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
211 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
212 1f / 60f,
213 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
214 (s) => { return (float)s.m_fixedTimeStep; },
215 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
216 new ParameterDefn("NominalFrameRate", "The base frame rate we claim",
217 55f,
218 (s,cf,p,v) => { s.NominalFrameRate = cf.GetInt(p, (int)v); },
219 (s) => { return (float)s.NominalFrameRate; },
220 (s,p,l,v) => { s.NominalFrameRate = (int)v; } ),
221 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
222 2048f,
223 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
224 (s) => { return (float)s.m_maxCollisionsPerFrame; },
225 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
226 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
227 8000f,
228 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
229 (s) => { return (float)s.m_maxUpdatesPerFrame; },
230 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
231 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
232 500f,
233 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
234 (s) => { return (float)s.m_taintsToProcessPerStep; },
235 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
236 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
237 0.0001f,
238 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
239 (s) => { return (float)MinimumObjectMass; },
240 (s,p,l,v) => { MinimumObjectMass = v; } ),
241 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
242 10000.01f,
243 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
244 (s) => { return (float)MaximumObjectMass; },
245 (s,p,l,v) => { MaximumObjectMass = v; } ),
246
247 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
248 2200f,
249 (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
250 (s) => { return (float)PID_D; },
251 (s,p,l,v) => { PID_D = v; } ),
252 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
253 900f,
254 (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
255 (s) => { return (float)PID_P; },
256 (s,p,l,v) => { PID_P = v; } ),
257
258 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
259 0.2f,
260 (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
261 (s) => { return s.UnmanagedParams[0].defaultFriction; },
262 (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
263 new ParameterDefn("DefaultDensity", "Density for new objects" ,
264 10.000006836f, // Aluminum g/cm3
265 (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
266 (s) => { return s.UnmanagedParams[0].defaultDensity; },
267 (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
268 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
269 0f,
270 (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
271 (s) => { return s.UnmanagedParams[0].defaultRestitution; },
272 (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
273 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
274 0.04f,
275 (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
276 (s) => { return s.UnmanagedParams[0].collisionMargin; },
277 (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
278 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
279 -9.80665f,
280 (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
281 (s) => { return s.UnmanagedParams[0].gravity; },
282 (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
283 (s,o,v) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,v)); } ),
284
285
286 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
287 0f,
288 (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
289 (s) => { return LinearDamping; },
290 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
291 (s,o,v) => { s.PE.SetDamping(o.PhysBody, v, AngularDamping); } ),
292 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
293 0f,
294 (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
295 (s) => { return AngularDamping; },
296 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
297 (s,o,v) => { s.PE.SetDamping(o.PhysBody, LinearDamping, v); } ),
298 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
299 0.2f,
300 (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
301 (s) => { return DeactivationTime; },
302 (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
303 (s,o,v) => { s.PE.SetDeactivationTime(o.PhysBody, v); } ),
304 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
305 0.8f,
306 (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
307 (s) => { return LinearSleepingThreshold; },
308 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
309 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
310 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
311 1.0f,
312 (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
313 (s) => { return AngularSleepingThreshold; },
314 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
315 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
316 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
317 0f, // set to zero to disable
318 (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
319 (s) => { return CcdMotionThreshold; },
320 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
321 (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ),
322 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
323 0f,
324 (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
325 (s) => { return CcdSweptSphereRadius; },
326 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
327 (s,o,v) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, v); } ),
328 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
329 0.1f,
330 (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
331 (s) => { return ContactProcessingThreshold; },
332 (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
333 (s,o,v) => { s.PE.SetContactProcessingThreshold(o.PhysBody, v); } ),
334
335 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
336 (float)BSTerrainPhys.TerrainImplementation.Mesh,
337 (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
338 (s) => { return TerrainImplementation; },
339 (s,p,l,v) => { TerrainImplementation = v; } ),
340 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
341 0.3f,
342 (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
343 (s) => { return TerrainFriction; },
344 (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
345 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
346 0.8f,
347 (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
348 (s) => { return TerrainHitFraction; },
349 (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
350 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
351 0f,
352 (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
353 (s) => { return TerrainRestitution; },
354 (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
355 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
356 0.04f,
357 (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
358 (s) => { return TerrainCollisionMargin; },
359 (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
360
361 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
362 0.2f,
363 (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); },
364 (s) => { return AvatarFriction; },
365 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
366 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
367 10.0f,
368 (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
369 (s) => { return AvatarStandingFriction; },
370 (s,p,l,v) => { AvatarStandingFriction = v; } ),
371 new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
372 1.3f,
373 (s,cf,p,v) => { AvatarAlwaysRunFactor = cf.GetFloat(p, v); },
374 (s) => { return AvatarAlwaysRunFactor; },
375 (s,p,l,v) => { AvatarAlwaysRunFactor = v; } ),
376 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
377 3.5f,
378 (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
379 (s) => { return AvatarDensity; },
380 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
381 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
382 0f,
383 (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
384 (s) => { return AvatarRestitution; },
385 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
386 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
387 0.6f,
388 (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
389 (s) => { return AvatarCapsuleWidth; },
390 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
391 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
392 0.45f,
393 (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
394 (s) => { return AvatarCapsuleDepth; },
395 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
396 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
397 1.5f,
398 (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
399 (s) => { return AvatarCapsuleHeight; },
400 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
401 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
402 0.1f,
403 (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
404 (s) => { return AvatarContactProcessingThreshold; },
405 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
406
407 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
408 0.95f,
409 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
410 (s) => { return VehicleAngularDamping; },
411 (s,p,l,v) => { VehicleAngularDamping = v; } ),
412
413 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
414 0f,
415 (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
416 (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
417 (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
418 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
419 0f,
420 (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
421 (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
422 (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
423 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
424 ConfigurationParameters.numericFalse,
425 (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
426 (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
427 (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
428 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
429 ConfigurationParameters.numericFalse,
430 (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
431 (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
432 (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
433 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
434 ConfigurationParameters.numericTrue,
435 (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
436 (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
437 (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
438 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
439 ConfigurationParameters.numericTrue,
440 (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
441 (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
442 (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
443 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
444 ConfigurationParameters.numericFalse,
445 (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
446 (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
447 (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
448 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
449 0f, // zero says use Bullet default
450 (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
451 (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
452 (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
453
454 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
455 (float)BSLinkset.LinksetImplementation.Compound,
456 (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
457 (s) => { return LinksetImplementation; },
458 (s,p,l,v) => { LinksetImplementation = v; } ),
459 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
460 ConfigurationParameters.numericFalse,
461 (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
462 (s) => { return LinkConstraintUseFrameOffset; },
463 (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
464 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
465 ConfigurationParameters.numericTrue,
466 (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
467 (s) => { return LinkConstraintEnableTransMotor; },
468 (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
469 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
470 5.0f,
471 (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
472 (s) => { return LinkConstraintTransMotorMaxVel; },
473 (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
474 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
475 0.1f,
476 (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
477 (s) => { return LinkConstraintTransMotorMaxForce; },
478 (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
479 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
480 0.1f,
481 (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
482 (s) => { return LinkConstraintCFM; },
483 (s,p,l,v) => { LinkConstraintCFM = v; } ),
484 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
485 0.1f,
486 (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
487 (s) => { return LinkConstraintERP; },
488 (s,p,l,v) => { LinkConstraintERP = v; } ),
489 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
490 40,
491 (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
492 (s) => { return LinkConstraintSolverIterations; },
493 (s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
494
495 new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
496 0f,
497 (s,cf,p,v) => { s.PhysicsMetricDumpFrames = cf.GetFloat(p, (int)v); },
498 (s) => { return (float)s.PhysicsMetricDumpFrames; },
499 (s,p,l,v) => { s.PhysicsMetricDumpFrames = (int)v; } ),
500 };
501
502 // Convert a boolean to our numeric true and false values
503 public static float NumericBool(bool b)
504 {
505 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
506 }
507
508 // Convert numeric true and false values to a boolean
509 public static bool BoolNumeric(float b)
510 {
511 return (b == ConfigurationParameters.numericTrue ? true : false);
512 }
513
514 // Search through the parameter definitions and return the matching
515 // ParameterDefn structure.
516 // Case does not matter as names are compared after converting to lower case.
517 // Returns 'false' if the parameter is not found.
518 internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
519 {
520 bool ret = false;
521 ParameterDefn foundDefn = new ParameterDefn();
522 string pName = paramName.ToLower();
523
524 foreach (ParameterDefn parm in ParameterDefinitions)
525 {
526 if (pName == parm.name.ToLower())
527 {
528 foundDefn = parm;
529 ret = true;
530 break;
531 }
532 }
533 defn = foundDefn;
534 return ret;
535 }
536
537 // Pass through the settable parameters and set the default values
538 internal static void SetParameterDefaultValues(BSScene physicsScene)
539 {
540 foreach (ParameterDefn parm in ParameterDefinitions)
541 {
542 parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
543 }
544 }
545
546 // Get user set values out of the ini file.
547 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
548 {
549 foreach (ParameterDefn parm in ParameterDefinitions)
550 {
551 parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
552 }
553 }
554
555 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
556
557 // This creates an array in the correct format for returning the list of
558 // parameters. This is used by the 'list' option of the 'physics' command.
559 internal static void BuildParameterTable()
560 {
561 if (SettableParameters.Length < ParameterDefinitions.Length)
562 {
563 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
564 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
565 {
566 ParameterDefn pd = ParameterDefinitions[ii];
567 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
568 }
569
570 // make the list in alphabetical order for estetic reasons
571 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
572 {
573 return ppe1.name.CompareTo(ppe2.name);
574 });
575
576 SettableParameters = entries.ToArray();
577 }
578 }
579
580
581}
582}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
deleted file mode 100755
index e7cb3e0..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ /dev/null
@@ -1,386 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.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 two (and certainly the last one) should be referenced only 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
58public abstract class BSPhysObject : PhysicsActor
59{
60 protected BSPhysObject()
61 {
62 }
63 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
64 {
65 PhysicsScene = parentScene;
66 LocalID = localID;
67 PhysObjectName = name;
68 TypeName = typeName;
69
70 // We don't have any physical representation yet.
71 PhysBody = new BulletBody(localID);
72 PhysShape = new BulletShape();
73
74 // A linkset of just me
75 Linkset = BSLinkset.Factory(PhysicsScene, this);
76 LastAssetBuildFailed = false;
77
78 // Default material type
79 Material = MaterialAttributes.Material.Wood;
80
81 CollisionCollection = new CollisionEventUpdate();
82 SubscribedEventsMs = 0;
83 CollidingStep = 0;
84 CollidingGroundStep = 0;
85 }
86
87 // Tell the object to clean up.
88 public virtual void Destroy()
89 {
90 UnRegisterAllPreStepActions();
91 }
92
93 public BSScene PhysicsScene { get; protected set; }
94 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
95 public string PhysObjectName { get; protected set; }
96 public string TypeName { get; protected set; }
97
98 public BSLinkset Linkset { get; set; }
99 public BSLinksetInfo LinksetInfo { get; set; }
100
101 // Return the object mass without calculating it or having side effects
102 public abstract float RawMass { get; }
103 // Set the raw mass but also update physical mass properties (inertia, ...)
104 // 'inWorld' true if the object has already been added to the dynamic world.
105 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
106
107 // The last value calculated for the prim's inertia
108 public OMV.Vector3 Inertia { get; set; }
109
110 // Reference to the physical body (btCollisionObject) of this object
111 public BulletBody PhysBody;
112 // Reference to the physical shape (btCollisionShape) of this object
113 public BulletShape PhysShape;
114
115 // 'true' if the mesh's underlying asset failed to build.
116 // This will keep us from looping after the first time the build failed.
117 public bool LastAssetBuildFailed { get; set; }
118
119 // The objects base shape information. Null if not a prim type shape.
120 public PrimitiveBaseShape BaseShape { get; protected set; }
121 // Some types of objects have preferred physical representations.
122 // Returns SHAPE_UNKNOWN if there is no preference.
123 public virtual BSPhysicsShapeType PreferredPhysicalShape
124 {
125 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
126 }
127
128 // When the physical properties are updated, an EntityProperty holds the update values.
129 // Keep the current and last EntityProperties to enable computation of differences
130 // between the current update and the previous values.
131 public EntityProperties CurrentEntityProperties { get; set; }
132 public EntityProperties LastEntityProperties { get; set; }
133
134 public virtual OMV.Vector3 Scale { get; set; }
135 public abstract bool IsSolid { get; }
136 public abstract bool IsStatic { get; }
137
138 // Materialness
139 public MaterialAttributes.Material Material { get; private set; }
140 public override void SetMaterial(int material)
141 {
142 Material = (MaterialAttributes.Material)material;
143 }
144
145 // Stop all physical motion.
146 public abstract void ZeroMotion(bool inTaintTime);
147 public abstract void ZeroAngularMotion(bool inTaintTime);
148
149 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
150 public virtual void StepVehicle(float timeStep) { }
151
152 // Update the physical location and motion of the object. Called with data from Bullet.
153 public abstract void UpdateProperties(EntityProperties entprop);
154
155 public abstract OMV.Vector3 RawPosition { get; set; }
156 public abstract OMV.Vector3 ForcePosition { get; set; }
157
158 public abstract OMV.Quaternion RawOrientation { get; set; }
159 public abstract OMV.Quaternion ForceOrientation { get; set; }
160
161 // The system is telling us the velocity it wants to move at.
162 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
163 public override OMV.Vector3 TargetVelocity
164 {
165 get { return m_targetVelocity; }
166 set
167 {
168 m_targetVelocity = value;
169 Velocity = value;
170 }
171 }
172 public abstract OMV.Vector3 ForceVelocity { get; set; }
173
174 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
175
176 public abstract float ForceBuoyancy { get; set; }
177
178 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
179
180 #region Collisions
181
182 // Requested number of milliseconds between collision events. Zero means disabled.
183 protected int SubscribedEventsMs { get; set; }
184 // Given subscription, the time that a collision may be passed up
185 protected int NextCollisionOkTime { get; set; }
186 // The simulation step that last had a collision
187 protected long CollidingStep { get; set; }
188 // The simulation step that last had a collision with the ground
189 protected long CollidingGroundStep { get; set; }
190 // The simulation step that last collided with an object
191 protected long CollidingObjectStep { get; set; }
192 // The collision flags we think are set in Bullet
193 protected CollisionFlags CurrentCollisionFlags { get; set; }
194
195 public override bool IsColliding {
196 get { return (CollidingStep == PhysicsScene.SimulationStep); }
197 set {
198 if (value)
199 CollidingStep = PhysicsScene.SimulationStep;
200 else
201 CollidingStep = 0;
202 }
203 }
204 public override bool CollidingGround {
205 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
206 set
207 {
208 if (value)
209 CollidingGroundStep = PhysicsScene.SimulationStep;
210 else
211 CollidingGroundStep = 0;
212 }
213 }
214 public override bool CollidingObj {
215 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
216 set {
217 if (value)
218 CollidingObjectStep = PhysicsScene.SimulationStep;
219 else
220 CollidingObjectStep = 0;
221 }
222 }
223
224 // The collisions that have been collected this tick
225 protected CollisionEventUpdate CollisionCollection;
226
227 // The simulation step is telling this object about a collision.
228 // Return 'true' if a collision was processed and should be sent up.
229 // Called at taint time from within the Step() function
230 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
231 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
232 {
233 bool ret = false;
234
235 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
236 CollidingStep = PhysicsScene.SimulationStep;
237 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
238 {
239 CollidingGroundStep = PhysicsScene.SimulationStep;
240 }
241 else
242 {
243 CollidingObjectStep = PhysicsScene.SimulationStep;
244 }
245
246 // prims in the same linkset cannot collide with each other
247 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
248 {
249 return ret;
250 }
251
252 // if someone has subscribed for collision events....
253 if (SubscribedEvents()) {
254 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
255 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
256 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
257
258 ret = true;
259 }
260 return ret;
261 }
262
263 // Send the collected collisions into the simulator.
264 // Called at taint time from within the Step() function thus no locking problems
265 // with CollisionCollection and ObjectsWithNoMoreCollisions.
266 // Return 'true' if there were some actual collisions passed up
267 public virtual bool SendCollisions()
268 {
269 bool ret = true;
270 // If the 'no collision' call, force it to happen right now so quick collision_end
271 bool force = (CollisionCollection.Count == 0);
272
273 // throttle the collisions to the number of milliseconds specified in the subscription
274 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
275 {
276 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
277
278 // We are called if we previously had collisions. If there are no collisions
279 // this time, send up one last empty event so OpenSim can sense collision end.
280 if (CollisionCollection.Count == 0)
281 {
282 // If I have no collisions this time, remove me from the list of objects with collisions.
283 ret = false;
284 }
285
286 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
287 base.SendCollisionUpdate(CollisionCollection);
288
289 // The CollisionCollection instance is passed around in the simulator.
290 // Make sure we don't have a handle to that one and that a new one is used for next time.
291 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
292 // a race condition is created for the other users of this instance.
293 CollisionCollection = new CollisionEventUpdate();
294 }
295 return ret;
296 }
297
298 // Subscribe for collision events.
299 // Parameter is the millisecond rate the caller wishes collision events to occur.
300 public override void SubscribeEvents(int ms) {
301 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
302 SubscribedEventsMs = ms;
303 if (ms > 0)
304 {
305 // make sure first collision happens
306 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
307
308 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
309 {
310 if (PhysBody.HasPhysicalBody)
311 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
312 });
313 }
314 else
315 {
316 // Subscribing for zero or less is the same as unsubscribing
317 UnSubscribeEvents();
318 }
319 }
320 public override void UnSubscribeEvents() {
321 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
322 SubscribedEventsMs = 0;
323 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
324 {
325 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
326 if (PhysBody.HasPhysicalBody)
327 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
328 });
329 }
330 // Return 'true' if the simulator wants collision events
331 public override bool SubscribedEvents() {
332 return (SubscribedEventsMs > 0);
333 }
334
335 #endregion // Collisions
336
337 #region Per Simulation Step actions
338 // There are some actions that must be performed for a physical object before each simulation step.
339 // These actions are optional so, rather than scanning all the physical objects and asking them
340 // if they have anything to do, a physical object registers for an event call before the step is performed.
341 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
342 private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
343 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
344 {
345 string identifier = op + "-" + id.ToString();
346 RegisteredActions[identifier] = actn;
347 PhysicsScene.BeforeStep += actn;
348 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
349 }
350
351 // Unregister a pre step action. Safe to call if the action has not been registered.
352 protected void UnRegisterPreStepAction(string op, uint id)
353 {
354 string identifier = op + "-" + id.ToString();
355 bool removed = false;
356 if (RegisteredActions.ContainsKey(identifier))
357 {
358 PhysicsScene.BeforeStep -= RegisteredActions[identifier];
359 RegisteredActions.Remove(identifier);
360 removed = true;
361 }
362 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
363 }
364
365 protected void UnRegisterAllPreStepActions()
366 {
367 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
368 {
369 PhysicsScene.BeforeStep -= kvp.Value;
370 }
371 RegisteredActions.Clear();
372 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
373 }
374
375
376 #endregion // Per Simulation Step actions
377
378 // High performance detailed logging routine used by the physical objects.
379 protected void DetailLog(string msg, params Object[] args)
380 {
381 if (PhysicsScene.PhysicsLogging.Enabled)
382 PhysicsScene.DetailLog(msg, args);
383 }
384
385}
386}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
deleted file mode 100644
index 65be52a..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ /dev/null
@@ -1,76 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.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(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/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
deleted file mode 100644
index 826261c..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ /dev/null
@@ -1,1513 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
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;
37
38namespace OpenSim.Region.Physics.BulletSPlugin
39{
40
41 [Serializable]
42public sealed class BSPrim : BSPhysObject
43{
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static readonly string LogHeader = "[BULLETS PRIM]";
46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
49
50 private bool _grabbed;
51 private bool _isSelected;
52 private bool _isVolumeDetect;
53 private OMV.Vector3 _position;
54 private float _mass; // the mass of this object
55 private float _density;
56 private OMV.Vector3 _force;
57 private OMV.Vector3 _velocity;
58 private OMV.Vector3 _torque;
59 private float _collisionScore;
60 private OMV.Vector3 _acceleration;
61 private OMV.Quaternion _orientation;
62 private int _physicsActorType;
63 private bool _isPhysical;
64 private bool _flying;
65 private float _friction;
66 private float _restitution;
67 private bool _setAlwaysRun;
68 private bool _throttleUpdates;
69 private bool _isColliding;
70 private bool _collidingGround;
71 private bool _collidingObj;
72 private bool _floatOnWater;
73 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic;
75 private float _buoyancy;
76
77 private BSDynamics _vehicle;
78
79 private OMV.Vector3 _PIDTarget;
80 private bool _usePID;
81 private float _PIDTau;
82 private bool _useHoverPID;
83 private float _PIDHoverHeight;
84 private PIDHoverType _PIDHoverType;
85 private float _PIDHoverTao;
86
87 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
88 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
89 : base(parent_scene, localID, primName, "BSPrim")
90 {
91 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
92 _physicsActorType = (int)ActorTypes.Prim;
93 _position = pos;
94 _size = size;
95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
96 _orientation = rotation;
97 _buoyancy = 0f;
98 _velocity = OMV.Vector3.Zero;
99 _rotationalVelocity = OMV.Vector3.Zero;
100 BaseShape = pbs;
101 _isPhysical = pisPhysical;
102 _isVolumeDetect = false;
103
104 // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
105 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
106 _density = PhysicsScene.Params.defaultDensity;
107 _friction = PhysicsScene.Params.defaultFriction;
108 _restitution = PhysicsScene.Params.defaultRestitution;
109
110 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
111
112 _mass = CalculateMass();
113
114 // Cause linkset variables to be initialized (like mass)
115 Linkset.Refresh(this);
116
117 DetailLog("{0},BSPrim.constructor,call", LocalID);
118 // do the actual object creation at taint time
119 PhysicsScene.TaintedObject("BSPrim.create", delegate()
120 {
121 CreateGeomAndObject(true);
122
123 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody);
124 });
125 }
126
127 // called when this prim is being destroyed and we should free all the resources
128 public override void Destroy()
129 {
130 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
131 base.Destroy();
132
133 // Undo any links between me and any other object
134 BSPhysObject parentBefore = Linkset.LinksetRoot;
135 int childrenBefore = Linkset.NumberOfChildren;
136
137 Linkset = Linkset.RemoveMeFromLinkset(this);
138
139 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
140 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
141
142 // Undo any vehicle properties
143 this.VehicleType = (int)Vehicle.TYPE_NONE;
144
145 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
146 {
147 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
148 // If there are physical body and shape, release my use of same.
149 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
150 PhysBody.Clear();
151 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
152 PhysShape.Clear();
153 });
154 }
155
156 // No one uses this property.
157 public override bool Stopped {
158 get { return false; }
159 }
160 public override OMV.Vector3 Size {
161 get { return _size; }
162 set {
163 // We presume the scale and size are the same. If scale must be changed for
164 // the physical shape, that is done when the geometry is built.
165 _size = value;
166 Scale = _size;
167 ForceBodyShapeRebuild(false);
168 }
169 }
170
171 public override PrimitiveBaseShape Shape {
172 set {
173 BaseShape = value;
174 ForceBodyShapeRebuild(false);
175 }
176 }
177 // Whatever the linkset wants is what I want.
178 public override BSPhysicsShapeType PreferredPhysicalShape
179 { get { return Linkset.PreferredPhysicalShape(this); } }
180
181 public override bool ForceBodyShapeRebuild(bool inTaintTime)
182 {
183 LastAssetBuildFailed = false;
184 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
185 {
186 _mass = CalculateMass(); // changing the shape changes the mass
187 CreateGeomAndObject(true);
188 });
189 return true;
190 }
191 public override bool Grabbed {
192 set { _grabbed = value;
193 }
194 }
195 public override bool Selected {
196 set
197 {
198 if (value != _isSelected)
199 {
200 _isSelected = value;
201 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
202 {
203 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
204 SetObjectDynamic(false);
205 });
206 }
207 }
208 }
209 public override void CrossingFailure() { return; }
210
211 // link me to the specified parent
212 public override void link(PhysicsActor obj) {
213 BSPrim parent = obj as BSPrim;
214 if (parent != null)
215 {
216 BSPhysObject parentBefore = Linkset.LinksetRoot;
217 int childrenBefore = Linkset.NumberOfChildren;
218
219 Linkset = parent.Linkset.AddMeToLinkset(this);
220
221 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
222 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
223 }
224 return;
225 }
226
227 // delink me from my linkset
228 public override void delink() {
229 // TODO: decide if this parent checking needs to happen at taint time
230 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
231
232 BSPhysObject parentBefore = Linkset.LinksetRoot;
233 int childrenBefore = Linkset.NumberOfChildren;
234
235 Linkset = Linkset.RemoveMeFromLinkset(this);
236
237 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
238 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
239 return;
240 }
241
242 // Set motion values to zero.
243 // Do it to the properties so the values get set in the physics engine.
244 // Push the setting of the values to the viewer.
245 // Called at taint time!
246 public override void ZeroMotion(bool inTaintTime)
247 {
248 _velocity = OMV.Vector3.Zero;
249 _acceleration = OMV.Vector3.Zero;
250 _rotationalVelocity = OMV.Vector3.Zero;
251
252 // Zero some other properties in the physics engine
253 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
254 {
255 if (PhysBody.HasPhysicalBody)
256 PhysicsScene.PE.ClearAllForces(PhysBody);
257 });
258 }
259 public override void ZeroAngularMotion(bool inTaintTime)
260 {
261 _rotationalVelocity = OMV.Vector3.Zero;
262 // Zero some other properties in the physics engine
263 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
264 {
265 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
266 if (PhysBody.HasPhysicalBody)
267 {
268 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
269 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
270 }
271 });
272 }
273
274 public override void LockAngularMotion(OMV.Vector3 axis)
275 {
276 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
277 return;
278 }
279
280 public override OMV.Vector3 RawPosition
281 {
282 get { return _position; }
283 set { _position = value; }
284 }
285 public override OMV.Vector3 Position {
286 get {
287 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
288 * and does not fetch this position info for children. Thus this is commented out.
289 // child prims move around based on their parent. Need to get the latest location
290 if (!Linkset.IsRoot(this))
291 _position = Linkset.PositionGet(this);
292 */
293
294 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
295 // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody);
296 return _position;
297 }
298 set {
299 // If the position must be forced into the physics engine, use ForcePosition.
300 // All positions are given in world positions.
301 if (_position == value)
302 {
303 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
304 return;
305 }
306 _position = value;
307 PositionSanityCheck(false);
308
309 // A linkset might need to know if a component information changed.
310 Linkset.UpdateProperties(this, false);
311
312 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
313 {
314 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
315 ForcePosition = _position;
316 });
317 }
318 }
319 public override OMV.Vector3 ForcePosition {
320 get {
321 _position = PhysicsScene.PE.GetPosition(PhysBody);
322 return _position;
323 }
324 set {
325 _position = value;
326 if (PhysBody.HasPhysicalBody)
327 {
328 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
329 ActivateIfPhysical(false);
330 }
331 }
332 }
333
334 // Check that the current position is sane and, if not, modify the position to make it so.
335 // Check for being below terrain and being out of bounds.
336 // Returns 'true' of the position was made sane by some action.
337 private bool PositionSanityCheck(bool inTaintTime)
338 {
339 bool ret = false;
340
341 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
342 {
343 // The physical object is out of the known/simulated area.
344 // Upper levels of code will handle the transition to other areas so, for
345 // the time, we just ignore the position.
346 return ret;
347 }
348
349 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
350 OMV.Vector3 upForce = OMV.Vector3.Zero;
351 if (RawPosition.Z < terrainHeight)
352 {
353 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
354 float targetHeight = terrainHeight + (Size.Z / 2f);
355 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
356 upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
357 ret = true;
358 }
359
360 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
361 {
362 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
363 // TODO: a floating motor so object will bob in the water
364 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
365 {
366 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
367 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
368 ret = true;
369 }
370 }
371
372 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
373 // TODO: This should be intergrated with a geneal physics action mechanism.
374 // TODO: This should be moderated with PID'ness.
375 if (ret)
376 {
377 // Apply upforce and overcome gravity.
378 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
379 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
380 AddForce(correctionForce, false, inTaintTime);
381 }
382 return ret;
383 }
384
385 // Return the effective mass of the object.
386 // The definition of this call is to return the mass of the prim.
387 // If the simulator cares about the mass of the linkset, it will sum it itself.
388 public override float Mass
389 {
390 get
391 {
392 return _mass;
393 }
394 }
395
396 // used when we only want this prim's mass and not the linkset thing
397 public override float RawMass {
398 get { return _mass; }
399 }
400 // Set the physical mass to the passed mass.
401 // Note that this does not change _mass!
402 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
403 {
404 if (PhysBody.HasPhysicalBody)
405 {
406 if (IsStatic)
407 {
408 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity);
409 Inertia = OMV.Vector3.Zero;
410 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia);
411 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
412 }
413 else
414 {
415 OMV.Vector3 grav = ComputeGravity();
416
417 if (inWorld)
418 {
419 // Changing interesting properties doesn't change proxy and collision cache
420 // information. The Bullet solution is to re-add the object to the world
421 // after parameters are changed.
422 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
423 }
424
425 // The computation of mass props requires gravity to be set on the object.
426 PhysicsScene.PE.SetGravity(PhysBody, grav);
427
428 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
429 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
430 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
431
432 // center of mass is at the zero of the object
433 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation);
434 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld);
435
436 if (inWorld)
437 {
438 AddObjectToPhysicalWorld();
439 }
440
441 // Must set gravity after it has been added to the world because, for unknown reasons,
442 // adding the object resets the object's gravity to world gravity
443 PhysicsScene.PE.SetGravity(PhysBody, grav);
444
445 }
446 }
447 }
448
449 // Return what gravity should be set to this very moment
450 private OMV.Vector3 ComputeGravity()
451 {
452 OMV.Vector3 ret = PhysicsScene.DefaultGravity;
453
454 if (!IsStatic)
455 ret *= (1f - Buoyancy);
456
457 return ret;
458 }
459
460 // Is this used?
461 public override OMV.Vector3 CenterOfMass
462 {
463 get { return Linkset.CenterOfMass; }
464 }
465
466 // Is this used?
467 public override OMV.Vector3 GeometricCenter
468 {
469 get { return Linkset.GeometricCenter; }
470 }
471
472 public override OMV.Vector3 Force {
473 get { return _force; }
474 set {
475 _force = value;
476 if (_force != OMV.Vector3.Zero)
477 {
478 // If the force is non-zero, it must be reapplied each tick because
479 // Bullet clears the forces applied last frame.
480 RegisterPreStepAction("BSPrim.setForce", LocalID,
481 delegate(float timeStep)
482 {
483 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
484 if (PhysBody.HasPhysicalBody)
485 {
486 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
487 ActivateIfPhysical(false);
488 }
489 }
490 );
491 }
492 else
493 {
494 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
495 }
496 }
497 }
498
499 public override int VehicleType {
500 get {
501 return (int)_vehicle.Type; // if we are a vehicle, return that type
502 }
503 set {
504 Vehicle type = (Vehicle)value;
505
506 PhysicsScene.TaintedObject("setVehicleType", delegate()
507 {
508 // Done at taint time so we're sure the physics engine is not using the variables
509 // Vehicle code changes the parameters for this vehicle type.
510 _vehicle.ProcessTypeChange(type);
511 ActivateIfPhysical(false);
512
513 // If an active vehicle, register the vehicle code to be called before each step
514 if (_vehicle.Type == Vehicle.TYPE_NONE)
515 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
516 else
517 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
518 });
519 }
520 }
521 public override void VehicleFloatParam(int param, float value)
522 {
523 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
524 {
525 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
526 ActivateIfPhysical(false);
527 });
528 }
529 public override void VehicleVectorParam(int param, OMV.Vector3 value)
530 {
531 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
532 {
533 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
534 ActivateIfPhysical(false);
535 });
536 }
537 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
538 {
539 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
540 {
541 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
542 ActivateIfPhysical(false);
543 });
544 }
545 public override void VehicleFlags(int param, bool remove)
546 {
547 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
548 {
549 _vehicle.ProcessVehicleFlags(param, remove);
550 });
551 }
552
553 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
554 public override void SetVolumeDetect(int param) {
555 bool newValue = (param != 0);
556 if (_isVolumeDetect != newValue)
557 {
558 _isVolumeDetect = newValue;
559 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
560 {
561 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
562 SetObjectDynamic(true);
563 });
564 }
565 return;
566 }
567 public override OMV.Vector3 Velocity {
568 get { return _velocity; }
569 set {
570 _velocity = value;
571 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
572 {
573 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
574 ForceVelocity = _velocity;
575 });
576 }
577 }
578 public override OMV.Vector3 ForceVelocity {
579 get { return _velocity; }
580 set {
581 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
582
583 _velocity = value;
584 if (PhysBody.HasPhysicalBody)
585 {
586 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
587 ActivateIfPhysical(false);
588 }
589 }
590 }
591 public override OMV.Vector3 Torque {
592 get { return _torque; }
593 set {
594 _torque = value;
595 if (_torque != OMV.Vector3.Zero)
596 {
597 // If the torque is non-zero, it must be reapplied each tick because
598 // Bullet clears the forces applied last frame.
599 RegisterPreStepAction("BSPrim.setTorque", LocalID,
600 delegate(float timeStep)
601 {
602 if (PhysBody.HasPhysicalBody)
603 AddAngularForce(_torque, false, true);
604 }
605 );
606 }
607 else
608 {
609 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
610 }
611 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
612 }
613 }
614 public override float CollisionScore {
615 get { return _collisionScore; }
616 set { _collisionScore = value;
617 }
618 }
619 public override OMV.Vector3 Acceleration {
620 get { return _acceleration; }
621 set { _acceleration = value; }
622 }
623 public override OMV.Quaternion RawOrientation
624 {
625 get { return _orientation; }
626 set { _orientation = value; }
627 }
628 public override OMV.Quaternion Orientation {
629 get {
630 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
631 * and does not fetch this position info for children. Thus this is commented out.
632 // Children move around because tied to parent. Get a fresh value.
633 if (!Linkset.IsRoot(this))
634 {
635 _orientation = Linkset.OrientationGet(this);
636 }
637 */
638 return _orientation;
639 }
640 set {
641 if (_orientation == value)
642 return;
643 _orientation = value;
644
645 // A linkset might need to know if a component information changed.
646 Linkset.UpdateProperties(this, false);
647
648 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
649 {
650 if (PhysBody.HasPhysicalBody)
651 {
652 // _position = PhysicsScene.PE.GetObjectPosition(PhysicsScene.World, BSBody);
653 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
654 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
655 }
656 });
657 }
658 }
659 // Go directly to Bullet to get/set the value.
660 public override OMV.Quaternion ForceOrientation
661 {
662 get
663 {
664 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
665 return _orientation;
666 }
667 set
668 {
669 _orientation = value;
670 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
671 }
672 }
673 public override int PhysicsActorType {
674 get { return _physicsActorType; }
675 set { _physicsActorType = value; }
676 }
677 public override bool IsPhysical {
678 get { return _isPhysical; }
679 set {
680 if (_isPhysical != value)
681 {
682 _isPhysical = value;
683 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
684 {
685 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
686 SetObjectDynamic(true);
687 // whether phys-to-static or static-to-phys, the object is not moving.
688 ZeroMotion(true);
689 });
690 }
691 }
692 }
693
694 // An object is static (does not move) if selected or not physical
695 public override bool IsStatic
696 {
697 get { return _isSelected || !IsPhysical; }
698 }
699
700 // An object is solid if it's not phantom and if it's not doing VolumeDetect
701 public override bool IsSolid
702 {
703 get { return !IsPhantom && !_isVolumeDetect; }
704 }
705
706 // Make gravity work if the object is physical and not selected
707 // Called at taint-time!!
708 private void SetObjectDynamic(bool forceRebuild)
709 {
710 // Recreate the physical object if necessary
711 CreateGeomAndObject(forceRebuild);
712 }
713
714 // Convert the simulator's physical properties into settings on BulletSim objects.
715 // There are four flags we're interested in:
716 // IsStatic: Object does not move, otherwise the object has mass and moves
717 // isSolid: other objects bounce off of this object
718 // isVolumeDetect: other objects pass through but can generate collisions
719 // collisionEvents: whether this object returns collision events
720 private void UpdatePhysicalParameters()
721 {
722 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
723
724 // Mangling all the physical properties requires the object not be in the physical world.
725 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
726 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
727
728 // Set up the object physicalness (does gravity and collisions move this object)
729 MakeDynamic(IsStatic);
730
731 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
732 _vehicle.Refresh();
733
734 // Arrange for collision events if the simulator wants them
735 EnableCollisions(SubscribedEvents());
736
737 // Make solid or not (do things bounce off or pass through this object).
738 MakeSolid(IsSolid);
739
740 AddObjectToPhysicalWorld();
741
742 // Rebuild its shape
743 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
744
745 // Recompute any linkset parameters.
746 // When going from non-physical to physical, this re-enables the constraints that
747 // had been automatically disabled when the mass was set to zero.
748 // For compound based linksets, this enables and disables interactions of the children.
749 Linkset.Refresh(this);
750
751 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
752 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
753 }
754
755 // "Making dynamic" means changing to and from static.
756 // When static, gravity does not effect the object and it is fixed in space.
757 // When dynamic, the object can fall and be pushed by others.
758 // This is independent of its 'solidness' which controls what passes through
759 // this object and what interacts with it.
760 private void MakeDynamic(bool makeStatic)
761 {
762 if (makeStatic)
763 {
764 // Become a Bullet 'static' object type
765 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
766 // Stop all movement
767 ZeroMotion(true);
768
769 // Set various physical properties so other object interact properly
770 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
771 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
772 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
773
774 // Mass is zero which disables a bunch of physics stuff in Bullet
775 UpdatePhysicalMassProperties(0f, false);
776 // Set collision detection parameters
777 if (BSParam.CcdMotionThreshold > 0f)
778 {
779 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
780 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
781 }
782
783 // The activation state is 'disabled' so Bullet will not try to act on it.
784 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
785 // Start it out sleeping and physical actions could wake it up.
786 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
787
788 // This collides like a static object
789 PhysBody.collisionType = CollisionType.Static;
790
791 // There can be special things needed for implementing linksets
792 Linkset.MakeStatic(this);
793 }
794 else
795 {
796 // Not a Bullet static object
797 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
798
799 // Set various physical properties so other object interact properly
800 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
801 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
802 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
803
804 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
805 // Since this can be called multiple times, only zero forces when becoming physical
806 // PhysicsScene.PE.ClearAllForces(BSBody);
807
808 // For good measure, make sure the transform is set through to the motion state
809 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
810
811 // Center of mass is at the center of the object
812 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation);
813
814 // A dynamic object has mass
815 UpdatePhysicalMassProperties(RawMass, false);
816
817 // Set collision detection parameters
818 if (BSParam.CcdMotionThreshold > 0f)
819 {
820 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
821 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
822 }
823
824 // Various values for simulation limits
825 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
826 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
827 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
828 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
829
830 // This collides like an object.
831 PhysBody.collisionType = CollisionType.Dynamic;
832
833 // Force activation of the object so Bullet will act on it.
834 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
835 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
836
837 // There might be special things needed for implementing linksets.
838 Linkset.MakeDynamic(this);
839 }
840 }
841
842 // "Making solid" means that other object will not pass through this object.
843 // To make transparent, we create a Bullet ghost object.
844 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
845 // the functions after this one set up the state of a possibly newly created collision body.
846 private void MakeSolid(bool makeSolid)
847 {
848 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody);
849 if (makeSolid)
850 {
851 // Verify the previous code created the correct shape for this type of thing.
852 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
853 {
854 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
855 }
856 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
857 }
858 else
859 {
860 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
861 {
862 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
863 }
864 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
865
866 // Change collision info from a static object to a ghosty collision object
867 PhysBody.collisionType = CollisionType.VolumeDetect;
868 }
869 }
870
871 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
872 // they need waking up when parameters are changed.
873 // Called in taint-time!!
874 private void ActivateIfPhysical(bool forceIt)
875 {
876 if (IsPhysical && PhysBody.HasPhysicalBody)
877 PhysicsScene.PE.Activate(PhysBody, forceIt);
878 }
879
880 // Turn on or off the flag controlling whether collision events are returned to the simulator.
881 private void EnableCollisions(bool wantsCollisionEvents)
882 {
883 if (wantsCollisionEvents)
884 {
885 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
886 }
887 else
888 {
889 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
890 }
891 }
892
893 // Add me to the physical world.
894 // Object MUST NOT already be in the world.
895 // This routine exists because some assorted properties get mangled by adding to the world.
896 internal void AddObjectToPhysicalWorld()
897 {
898 if (PhysBody.HasPhysicalBody)
899 {
900 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
901 }
902 else
903 {
904 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
905 DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
906 }
907 }
908
909 // prims don't fly
910 public override bool Flying {
911 get { return _flying; }
912 set {
913 _flying = value;
914 }
915 }
916 public override bool SetAlwaysRun {
917 get { return _setAlwaysRun; }
918 set { _setAlwaysRun = value; }
919 }
920 public override bool ThrottleUpdates {
921 get { return _throttleUpdates; }
922 set { _throttleUpdates = value; }
923 }
924 public bool IsPhantom {
925 get {
926 // SceneObjectPart removes phantom objects from the physics scene
927 // so, although we could implement touching and such, we never
928 // are invoked as a phantom object
929 return false;
930 }
931 }
932 public override bool FloatOnWater {
933 set {
934 _floatOnWater = value;
935 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
936 {
937 if (_floatOnWater)
938 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
939 else
940 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
941 });
942 }
943 }
944 public override OMV.Vector3 RotationalVelocity {
945 get {
946 return _rotationalVelocity;
947 }
948 set {
949 _rotationalVelocity = value;
950 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
951 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
952 {
953 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
954 ForceRotationalVelocity = _rotationalVelocity;
955 });
956 }
957 }
958 public override OMV.Vector3 ForceRotationalVelocity {
959 get {
960 return _rotationalVelocity;
961 }
962 set {
963 _rotationalVelocity = value;
964 if (PhysBody.HasPhysicalBody)
965 {
966 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
967 ActivateIfPhysical(false);
968 }
969 }
970 }
971 public override bool Kinematic {
972 get { return _kinematic; }
973 set { _kinematic = value;
974 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
975 }
976 }
977 public override float Buoyancy {
978 get { return _buoyancy; }
979 set {
980 _buoyancy = value;
981 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
982 {
983 ForceBuoyancy = _buoyancy;
984 });
985 }
986 }
987 public override float ForceBuoyancy {
988 get { return _buoyancy; }
989 set {
990 _buoyancy = value;
991 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
992 // Force the recalculation of the various inertia,etc variables in the object
993 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass);
994 UpdatePhysicalMassProperties(_mass, true);
995 ActivateIfPhysical(false);
996 }
997 }
998
999 // Used for MoveTo
1000 public override OMV.Vector3 PIDTarget {
1001 set { _PIDTarget = value; }
1002 }
1003 public override float PIDTau {
1004 set { _PIDTau = value; }
1005 }
1006 public override bool PIDActive {
1007 set { _usePID = value; }
1008 }
1009
1010 // Used for llSetHoverHeight and maybe vehicle height
1011 // Hover Height will override MoveTo target's Z
1012 public override bool PIDHoverActive {
1013 set { _useHoverPID = value; }
1014 }
1015 public override float PIDHoverHeight {
1016 set { _PIDHoverHeight = value; }
1017 }
1018 public override PIDHoverType PIDHoverType {
1019 set { _PIDHoverType = value; }
1020 }
1021 public override float PIDHoverTau {
1022 set { _PIDHoverTao = value; }
1023 }
1024
1025 // For RotLookAt
1026 public override OMV.Quaternion APIDTarget { set { return; } }
1027 public override bool APIDActive { set { return; } }
1028 public override float APIDStrength { set { return; } }
1029 public override float APIDDamping { set { return; } }
1030
1031 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1032 // Since this force is being applied in only one step, make this a force per second.
1033 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
1034 AddForce(addForce, pushforce, false);
1035 }
1036 // Applying a force just adds this to the total force on the object.
1037 // This added force will only last the next simulation tick.
1038 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1039 // for an object, doesn't matter if force is a pushforce or not
1040 if (force.IsFinite())
1041 {
1042 float magnitude = force.Length();
1043 if (magnitude > BSParam.MaxAddForceMagnitude)
1044 {
1045 // Force has a limit
1046 force = force / magnitude * BSParam.MaxAddForceMagnitude;
1047 }
1048
1049 OMV.Vector3 addForce = force;
1050 DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1051
1052 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1053 {
1054 // Bullet adds this central force to the total force for this tick
1055 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1056 if (PhysBody.HasPhysicalBody)
1057 {
1058 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
1059 ActivateIfPhysical(false);
1060 }
1061 });
1062 }
1063 else
1064 {
1065 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1066 return;
1067 }
1068 }
1069
1070 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
1071 AddAngularForce(force, pushforce, false);
1072 }
1073 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1074 {
1075 if (force.IsFinite())
1076 {
1077 OMV.Vector3 angForce = force;
1078 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
1079 {
1080 if (PhysBody.HasPhysicalBody)
1081 {
1082 PhysicsScene.PE.ApplyTorque(PhysBody, angForce);
1083 ActivateIfPhysical(false);
1084 }
1085 });
1086 }
1087 else
1088 {
1089 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1090 return;
1091 }
1092 }
1093
1094 // A torque impulse.
1095 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1096 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1097 // Computed as: angularVelocity += impulse * inertia;
1098 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1099 {
1100 OMV.Vector3 applyImpulse = impulse;
1101 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1102 {
1103 if (PhysBody.HasPhysicalBody)
1104 {
1105 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1106 ActivateIfPhysical(false);
1107 }
1108 });
1109 }
1110
1111 public override void SetMomentum(OMV.Vector3 momentum) {
1112 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1113 }
1114 #region Mass Calculation
1115
1116 private float CalculateMass()
1117 {
1118 float volume = _size.X * _size.Y * _size.Z; // default
1119 float tmp;
1120
1121 float returnMass = 0;
1122 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1123 float hollowVolume = hollowAmount * hollowAmount;
1124
1125 switch (BaseShape.ProfileShape)
1126 {
1127 case ProfileShape.Square:
1128 // default box
1129
1130 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1131 {
1132 if (hollowAmount > 0.0)
1133 {
1134 switch (BaseShape.HollowShape)
1135 {
1136 case HollowShape.Square:
1137 case HollowShape.Same:
1138 break;
1139
1140 case HollowShape.Circle:
1141
1142 hollowVolume *= 0.78539816339f;
1143 break;
1144
1145 case HollowShape.Triangle:
1146
1147 hollowVolume *= (0.5f * .5f);
1148 break;
1149
1150 default:
1151 hollowVolume = 0;
1152 break;
1153 }
1154 volume *= (1.0f - hollowVolume);
1155 }
1156 }
1157
1158 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1159 {
1160 //a tube
1161
1162 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1163 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1164 volume -= volume*tmp*tmp;
1165
1166 if (hollowAmount > 0.0)
1167 {
1168 hollowVolume *= hollowAmount;
1169
1170 switch (BaseShape.HollowShape)
1171 {
1172 case HollowShape.Square:
1173 case HollowShape.Same:
1174 break;
1175
1176 case HollowShape.Circle:
1177 hollowVolume *= 0.78539816339f;;
1178 break;
1179
1180 case HollowShape.Triangle:
1181 hollowVolume *= 0.5f * 0.5f;
1182 break;
1183 default:
1184 hollowVolume = 0;
1185 break;
1186 }
1187 volume *= (1.0f - hollowVolume);
1188 }
1189 }
1190
1191 break;
1192
1193 case ProfileShape.Circle:
1194
1195 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1196 {
1197 volume *= 0.78539816339f; // elipse base
1198
1199 if (hollowAmount > 0.0)
1200 {
1201 switch (BaseShape.HollowShape)
1202 {
1203 case HollowShape.Same:
1204 case HollowShape.Circle:
1205 break;
1206
1207 case HollowShape.Square:
1208 hollowVolume *= 0.5f * 2.5984480504799f;
1209 break;
1210
1211 case HollowShape.Triangle:
1212 hollowVolume *= .5f * 1.27323954473516f;
1213 break;
1214
1215 default:
1216 hollowVolume = 0;
1217 break;
1218 }
1219 volume *= (1.0f - hollowVolume);
1220 }
1221 }
1222
1223 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1224 {
1225 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1226 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1227 volume *= (1.0f - tmp * tmp);
1228
1229 if (hollowAmount > 0.0)
1230 {
1231
1232 // calculate the hollow volume by it's shape compared to the prim shape
1233 hollowVolume *= hollowAmount;
1234
1235 switch (BaseShape.HollowShape)
1236 {
1237 case HollowShape.Same:
1238 case HollowShape.Circle:
1239 break;
1240
1241 case HollowShape.Square:
1242 hollowVolume *= 0.5f * 2.5984480504799f;
1243 break;
1244
1245 case HollowShape.Triangle:
1246 hollowVolume *= .5f * 1.27323954473516f;
1247 break;
1248
1249 default:
1250 hollowVolume = 0;
1251 break;
1252 }
1253 volume *= (1.0f - hollowVolume);
1254 }
1255 }
1256 break;
1257
1258 case ProfileShape.HalfCircle:
1259 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1260 {
1261 volume *= 0.52359877559829887307710723054658f;
1262 }
1263 break;
1264
1265 case ProfileShape.EquilateralTriangle:
1266
1267 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1268 {
1269 volume *= 0.32475953f;
1270
1271 if (hollowAmount > 0.0)
1272 {
1273
1274 // calculate the hollow volume by it's shape compared to the prim shape
1275 switch (BaseShape.HollowShape)
1276 {
1277 case HollowShape.Same:
1278 case HollowShape.Triangle:
1279 hollowVolume *= .25f;
1280 break;
1281
1282 case HollowShape.Square:
1283 hollowVolume *= 0.499849f * 3.07920140172638f;
1284 break;
1285
1286 case HollowShape.Circle:
1287 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1288 // Cyllinder hollow volume calculation
1289
1290 hollowVolume *= 0.1963495f * 3.07920140172638f;
1291 break;
1292
1293 default:
1294 hollowVolume = 0;
1295 break;
1296 }
1297 volume *= (1.0f - hollowVolume);
1298 }
1299 }
1300 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1301 {
1302 volume *= 0.32475953f;
1303 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1304 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1305 volume *= (1.0f - tmp * tmp);
1306
1307 if (hollowAmount > 0.0)
1308 {
1309
1310 hollowVolume *= hollowAmount;
1311
1312 switch (BaseShape.HollowShape)
1313 {
1314 case HollowShape.Same:
1315 case HollowShape.Triangle:
1316 hollowVolume *= .25f;
1317 break;
1318
1319 case HollowShape.Square:
1320 hollowVolume *= 0.499849f * 3.07920140172638f;
1321 break;
1322
1323 case HollowShape.Circle:
1324
1325 hollowVolume *= 0.1963495f * 3.07920140172638f;
1326 break;
1327
1328 default:
1329 hollowVolume = 0;
1330 break;
1331 }
1332 volume *= (1.0f - hollowVolume);
1333 }
1334 }
1335 break;
1336
1337 default:
1338 break;
1339 }
1340
1341
1342
1343 float taperX1;
1344 float taperY1;
1345 float taperX;
1346 float taperY;
1347 float pathBegin;
1348 float pathEnd;
1349 float profileBegin;
1350 float profileEnd;
1351
1352 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1353 {
1354 taperX1 = BaseShape.PathScaleX * 0.01f;
1355 if (taperX1 > 1.0f)
1356 taperX1 = 2.0f - taperX1;
1357 taperX = 1.0f - taperX1;
1358
1359 taperY1 = BaseShape.PathScaleY * 0.01f;
1360 if (taperY1 > 1.0f)
1361 taperY1 = 2.0f - taperY1;
1362 taperY = 1.0f - taperY1;
1363 }
1364 else
1365 {
1366 taperX = BaseShape.PathTaperX * 0.01f;
1367 if (taperX < 0.0f)
1368 taperX = -taperX;
1369 taperX1 = 1.0f - taperX;
1370
1371 taperY = BaseShape.PathTaperY * 0.01f;
1372 if (taperY < 0.0f)
1373 taperY = -taperY;
1374 taperY1 = 1.0f - taperY;
1375
1376 }
1377
1378
1379 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1380
1381 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1382 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1383 volume *= (pathEnd - pathBegin);
1384
1385 // this is crude aproximation
1386 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1387 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1388 volume *= (profileEnd - profileBegin);
1389
1390 returnMass = _density * volume;
1391
1392 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1393 if (IsRootOfLinkset)
1394 {
1395 foreach (BSPrim prim in _childrenPrims)
1396 {
1397 returnMass += prim.CalculateMass();
1398 }
1399 }
1400 */
1401
1402 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1403
1404 return returnMass;
1405 }// end CalculateMass
1406 #endregion Mass Calculation
1407
1408 // Rebuild the geometry and object.
1409 // This is called when the shape changes so we need to recreate the mesh/hull.
1410 // Called at taint-time!!!
1411 public void CreateGeomAndObject(bool forceRebuild)
1412 {
1413 // If this prim is part of a linkset, we must remove and restore the physical
1414 // links if the body is rebuilt.
1415 bool needToRestoreLinkset = false;
1416 bool needToRestoreVehicle = false;
1417
1418 // Create the correct physical representation for this type of object.
1419 // Updates PhysBody and PhysShape with the new information.
1420 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1421 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1422 {
1423 // Called if the current prim body is about to be destroyed.
1424 // Remove all the physical dependencies on the old body.
1425 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1426 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1427 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1428 });
1429
1430 if (needToRestoreLinkset)
1431 {
1432 // If physical body dependencies were removed, restore them
1433 Linkset.RestoreBodyDependencies(this);
1434 }
1435 if (needToRestoreVehicle)
1436 {
1437 // If physical body dependencies were removed, restore them
1438 _vehicle.RestoreBodyDependencies(this);
1439 }
1440
1441 // Make sure the properties are set on the new object
1442 UpdatePhysicalParameters();
1443 return;
1444 }
1445
1446 // The physics engine says that properties have updated. Update same and inform
1447 // the world that things have changed.
1448 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1449 enum UpdatedProperties {
1450 Position = 1 << 0,
1451 Rotation = 1 << 1,
1452 Velocity = 1 << 2,
1453 Acceleration = 1 << 3,
1454 RotationalVel = 1 << 4
1455 }
1456
1457 const float ROTATION_TOLERANCE = 0.01f;
1458 const float VELOCITY_TOLERANCE = 0.001f;
1459 const float POSITION_TOLERANCE = 0.05f;
1460 const float ACCELERATION_TOLERANCE = 0.01f;
1461 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1462
1463 public override void UpdateProperties(EntityProperties entprop)
1464 {
1465 // Updates only for individual prims and for the root object of a linkset.
1466 if (Linkset.IsRoot(this))
1467 {
1468 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1469 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1470 if (_vehicle.IsActive)
1471 {
1472 entprop.RotationalVelocity = OMV.Vector3.Zero;
1473 }
1474
1475 // Assign directly to the local variables so the normal set action does not happen
1476 _position = entprop.Position;
1477 _orientation = entprop.Rotation;
1478 _velocity = entprop.Velocity;
1479 _acceleration = entprop.Acceleration;
1480 _rotationalVelocity = entprop.RotationalVelocity;
1481
1482 // The sanity check can change the velocity and/or position.
1483 if (IsPhysical && PositionSanityCheck(true))
1484 {
1485 entprop.Position = _position;
1486 entprop.Velocity = _velocity;
1487 }
1488
1489 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1490 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1491 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1492
1493 // remember the current and last set values
1494 LastEntityProperties = CurrentEntityProperties;
1495 CurrentEntityProperties = entprop;
1496
1497 base.RequestPhysicsterseUpdate();
1498 }
1499 /*
1500 else
1501 {
1502 // For debugging, report the movement of children
1503 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1504 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1505 entprop.Acceleration, entprop.RotationalVelocity);
1506 }
1507 */
1508
1509 // The linkset implimentation might want to know about this.
1510 Linkset.UpdateProperties(this, true);
1511 }
1512}
1513}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
deleted file mode 100644
index 7017194..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ /dev/null
@@ -1,946 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using System.Runtime.InteropServices;
31using System.Text;
32using System.Threading;
33using OpenSim.Framework;
34using OpenSim.Region.Framework;
35using OpenSim.Region.CoreModules;
36using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
37using OpenSim.Region.Physics.Manager;
38using Nini.Config;
39using log4net;
40using OpenMetaverse;
41
42namespace OpenSim.Region.Physics.BulletSPlugin
43{
44public sealed class BSScene : PhysicsScene, IPhysicsParameters
45{
46 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
47 internal static readonly string LogHeader = "[BULLETS SCENE]";
48
49 // The name of the region we're working for.
50 public string RegionName { get; private set; }
51
52 public string BulletSimVersion = "?";
53
54 // The handle to the underlying managed or unmanaged version of Bullet being used.
55 public string BulletEngineName { get; private set; }
56 public BSAPITemplate PE;
57
58 public Dictionary<uint, BSPhysObject> PhysObjects;
59 public BSShapeCollection Shapes;
60
61 // Keeping track of the objects with collisions so we can report begin and end of a collision
62 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
63 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
64 // Keep track of all the avatars so we can send them a collision event
65 // every tick so OpenSim will update its animation.
66 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
67
68 // let my minuions use my logger
69 public ILog Logger { get { return m_log; } }
70
71 public IMesher mesher;
72 public uint WorldID { get; private set; }
73 public BulletWorld World { get; private set; }
74
75 // All the constraints that have been allocated in this instance.
76 public BSConstraintCollection Constraints { get; private set; }
77
78 // Simulation parameters
79 internal int m_maxSubSteps;
80 internal float m_fixedTimeStep;
81 internal long m_simulationStep = 0;
82 internal float NominalFrameRate { get; set; }
83 public long SimulationStep { get { return m_simulationStep; } }
84 internal int m_taintsToProcessPerStep;
85 internal float LastTimeStep { get; private set; }
86
87 // Physical objects can register for prestep or poststep events
88 public delegate void PreStepAction(float timeStep);
89 public delegate void PostStepAction(float timeStep);
90 public event PreStepAction BeforeStep;
91 public event PreStepAction AfterStep;
92
93 // A value of the time now so all the collision and update routines do not have to get their own
94 // Set to 'now' just before all the prims and actors are called for collisions and updates
95 public int SimulationNowTime { get; private set; }
96
97 // True if initialized and ready to do simulation steps
98 private bool m_initialized = false;
99
100 // Flag which is true when processing taints.
101 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
102 public bool InTaintTime { get; private set; }
103
104 // Pinned memory used to pass step information between managed and unmanaged
105 internal int m_maxCollisionsPerFrame;
106 internal CollisionDesc[] m_collisionArray;
107
108 internal int m_maxUpdatesPerFrame;
109 internal EntityProperties[] m_updateArray;
110
111 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
112 public const uint GROUNDPLANE_ID = 1;
113 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
114
115 public float SimpleWaterLevel { get; set; }
116 public BSTerrainManager TerrainManager { get; private set; }
117
118 public ConfigurationParameters Params
119 {
120 get { return UnmanagedParams[0]; }
121 }
122 public Vector3 DefaultGravity
123 {
124 get { return new Vector3(0f, 0f, Params.gravity); }
125 }
126 // Just the Z value of the gravity
127 public float DefaultGravityZ
128 {
129 get { return Params.gravity; }
130 }
131
132 // When functions in the unmanaged code must be called, it is only
133 // done at a known time just before the simulation step. The taint
134 // system saves all these function calls and executes them in
135 // order before the simulation.
136 public delegate void TaintCallback();
137 private struct TaintCallbackEntry
138 {
139 public String ident;
140 public TaintCallback callback;
141 public TaintCallbackEntry(string i, TaintCallback c)
142 {
143 ident = i;
144 callback = c;
145 }
146 }
147 private Object _taintLock = new Object(); // lock for using the next object
148 private List<TaintCallbackEntry> _taintOperations;
149 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
150 private List<TaintCallbackEntry> _postStepOperations;
151
152 // A pointer to an instance if this structure is passed to the C++ code
153 // Used to pass basic configuration values to the unmanaged code.
154 internal ConfigurationParameters[] UnmanagedParams;
155
156 // Sometimes you just have to log everything.
157 public Logging.LogWriter PhysicsLogging;
158 private bool m_physicsLoggingEnabled;
159 private string m_physicsLoggingDir;
160 private string m_physicsLoggingPrefix;
161 private int m_physicsLoggingFileMinutes;
162 private bool m_physicsLoggingDoFlush;
163 private bool m_physicsPhysicalDumpEnabled;
164 public float PhysicsMetricDumpFrames { get; set; }
165 // 'true' of the vehicle code is to log lots of details
166 public bool VehicleLoggingEnabled { get; private set; }
167 public bool VehiclePhysicalLoggingEnabled { get; private set; }
168
169 #region Construction and Initialization
170 public BSScene(string identifier)
171 {
172 m_initialized = false;
173 // we are passed the name of the region we're working for.
174 RegionName = identifier;
175 }
176
177 public override void Initialise(IMesher meshmerizer, IConfigSource config)
178 {
179 mesher = meshmerizer;
180 _taintOperations = new List<TaintCallbackEntry>();
181 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
182 _postStepOperations = new List<TaintCallbackEntry>();
183 PhysObjects = new Dictionary<uint, BSPhysObject>();
184 Shapes = new BSShapeCollection(this);
185
186 // Allocate pinned memory to pass parameters.
187 UnmanagedParams = new ConfigurationParameters[1];
188
189 // Set default values for physics parameters plus any overrides from the ini file
190 GetInitialParameterValues(config);
191
192 // Get the connection to the physics engine (could be native or one of many DLLs)
193 PE = SelectUnderlyingBulletEngine(BulletEngineName);
194
195 // Enable very detailed logging.
196 // By creating an empty logger when not logging, the log message invocation code
197 // can be left in and every call doesn't have to check for null.
198 if (m_physicsLoggingEnabled)
199 {
200 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
201 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
202 }
203 else
204 {
205 PhysicsLogging = new Logging.LogWriter();
206 }
207
208 // Allocate memory for returning of the updates and collisions from the physics engine
209 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
210 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
211
212 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
213 // a child in a mega-region.
214 // Bullet actually doesn't care about the extents of the simulated
215 // area. It tracks active objects no matter where they are.
216 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
217
218 World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
219
220 Constraints = new BSConstraintCollection(World);
221
222 TerrainManager = new BSTerrainManager(this);
223 TerrainManager.CreateInitialGroundPlaneAndTerrain();
224
225 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
226
227 InTaintTime = false;
228 m_initialized = true;
229 }
230
231 // All default parameter values are set here. There should be no values set in the
232 // variable definitions.
233 private void GetInitialParameterValues(IConfigSource config)
234 {
235 ConfigurationParameters parms = new ConfigurationParameters();
236 UnmanagedParams[0] = parms;
237
238 BSParam.SetParameterDefaultValues(this);
239
240 if (config != null)
241 {
242 // If there are specifications in the ini file, use those values
243 IConfig pConfig = config.Configs["BulletSim"];
244 if (pConfig != null)
245 {
246 BSParam.SetParameterConfigurationValues(this, pConfig);
247
248 // There are two Bullet implementations to choose from
249 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
250
251 // Very detailed logging for physics debugging
252 // TODO: the boolean values can be moved to the normal parameter processing.
253 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
254 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
255 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
256 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
257 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
258 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
259 // Very detailed logging for vehicle debugging
260 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
261 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
262
263 // Do any replacements in the parameters
264 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
265 }
266
267 // The material characteristics.
268 BSMaterials.InitializeFromDefaults(Params);
269 if (pConfig != null)
270 {
271 // Let the user add new and interesting material property values.
272 BSMaterials.InitializefromParameters(pConfig);
273 }
274 }
275 }
276
277 // A helper function that handles a true/false parameter and returns the proper float number encoding
278 float ParamBoolean(IConfig config, string parmName, float deflt)
279 {
280 float ret = deflt;
281 if (config.Contains(parmName))
282 {
283 ret = ConfigurationParameters.numericFalse;
284 if (config.GetBoolean(parmName, false))
285 {
286 ret = ConfigurationParameters.numericTrue;
287 }
288 }
289 return ret;
290 }
291
292 // Select the connection to the actual Bullet implementation.
293 // The main engine selection is the engineName up to the first hypen.
294 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
295 // is passed to the engine to do its special selection, etc.
296 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
297 {
298 // For the moment, do a simple switch statement.
299 // Someday do fancyness with looking up the interfaces in the assembly.
300 BSAPITemplate ret = null;
301
302 string selectionName = engineName.ToLower();
303 int hyphenIndex = engineName.IndexOf("-");
304 if (hyphenIndex > 0)
305 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
306
307 switch (selectionName)
308 {
309 case "bulletunmanaged":
310 ret = new BSAPIUnman(engineName, this);
311 break;
312 case "bulletxna":
313 ret = new BSAPIXNA(engineName, this);
314 break;
315 }
316
317 if (ret == null)
318 {
319 m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
320 }
321 else
322 {
323 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
324 }
325
326 return ret;
327 }
328
329 public override void Dispose()
330 {
331 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
332
333 // make sure no stepping happens while we're deleting stuff
334 m_initialized = false;
335
336 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
337 {
338 kvp.Value.Destroy();
339 }
340 PhysObjects.Clear();
341
342 // Now that the prims are all cleaned up, there should be no constraints left
343 if (Constraints != null)
344 {
345 Constraints.Dispose();
346 Constraints = null;
347 }
348
349 if (Shapes != null)
350 {
351 Shapes.Dispose();
352 Shapes = null;
353 }
354
355 if (TerrainManager != null)
356 {
357 TerrainManager.ReleaseGroundPlaneAndTerrain();
358 TerrainManager.Dispose();
359 TerrainManager = null;
360 }
361
362 // Anything left in the unmanaged code should be cleaned out
363 PE.Shutdown(World);
364
365 // Not logging any more
366 PhysicsLogging.Close();
367 }
368 #endregion // Construction and Initialization
369
370 #region Prim and Avatar addition and removal
371
372 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
373 {
374 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
375 return null;
376 }
377
378 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
379 {
380 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
381
382 if (!m_initialized) return null;
383
384 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
385 lock (PhysObjects) PhysObjects.Add(localID, actor);
386
387 // TODO: Remove kludge someday.
388 // We must generate a collision for avatars whether they collide or not.
389 // This is required by OpenSim to update avatar animations, etc.
390 lock (m_avatars) m_avatars.Add(actor);
391
392 return actor;
393 }
394
395 public override void RemoveAvatar(PhysicsActor actor)
396 {
397 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
398
399 if (!m_initialized) return;
400
401 BSCharacter bsactor = actor as BSCharacter;
402 if (bsactor != null)
403 {
404 try
405 {
406 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
407 // Remove kludge someday
408 lock (m_avatars) m_avatars.Remove(bsactor);
409 }
410 catch (Exception e)
411 {
412 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
413 }
414 bsactor.Destroy();
415 // bsactor.dispose();
416 }
417 }
418
419 public override void RemovePrim(PhysicsActor prim)
420 {
421 if (!m_initialized) return;
422
423 BSPrim bsprim = prim as BSPrim;
424 if (bsprim != null)
425 {
426 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
427 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
428 try
429 {
430 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
431 }
432 catch (Exception e)
433 {
434 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
435 }
436 bsprim.Destroy();
437 // bsprim.dispose();
438 }
439 else
440 {
441 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
442 }
443 }
444
445 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
446 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
447 {
448 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
449
450 if (!m_initialized) return null;
451
452 DetailLog("{0},AddPrimShape,call", localID);
453
454 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
455 lock (PhysObjects) PhysObjects.Add(localID, prim);
456 return prim;
457 }
458
459 // This is a call from the simulator saying that some physical property has been updated.
460 // The BulletSim driver senses the changing of relevant properties so this taint
461 // information call is not needed.
462 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
463
464 #endregion // Prim and Avatar addition and removal
465
466 #region Simulation
467 // Simulate one timestep
468 public override float Simulate(float timeStep)
469 {
470 // prevent simulation until we've been initialized
471 if (!m_initialized) return 5.0f;
472
473 LastTimeStep = timeStep;
474
475 int updatedEntityCount = 0;
476 int collidersCount = 0;
477
478 int beforeTime = 0;
479 int simTime = 0;
480
481 // update the prim states while we know the physics engine is not busy
482 int numTaints = _taintOperations.Count;
483
484 InTaintTime = true; // Only used for debugging so locking is not necessary.
485
486 ProcessTaints();
487
488 // Some of the physical objects requre individual, pre-step calls
489 TriggerPreStepEvent(timeStep);
490
491 // the prestep actions might have added taints
492 numTaints += _taintOperations.Count;
493 ProcessTaints();
494
495 InTaintTime = false; // Only used for debugging so locking is not necessary.
496
497 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
498 // Only enable this in a limited test world with few objects.
499 if (m_physicsPhysicalDumpEnabled)
500 PE.DumpAllInfo(World);
501
502 // step the physical world one interval
503 m_simulationStep++;
504 int numSubSteps = 0;
505 try
506 {
507 if (PhysicsLogging.Enabled)
508 beforeTime = Util.EnvironmentTickCount();
509
510 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
511
512 if (PhysicsLogging.Enabled)
513 {
514 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
515 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
516 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
517 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
518 }
519 }
520 catch (Exception e)
521 {
522 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
523 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
524 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
525 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
526 updatedEntityCount = 0;
527 collidersCount = 0;
528 }
529
530 if ((m_simulationStep % PhysicsMetricDumpFrames) == 0)
531 PE.DumpPhysicsStatistics(World);
532
533 // Get a value for 'now' so all the collision and update routines don't have to get their own.
534 SimulationNowTime = Util.EnvironmentTickCount();
535
536 // If there were collisions, process them by sending the event to the prim.
537 // Collisions must be processed before updates.
538 if (collidersCount > 0)
539 {
540 for (int ii = 0; ii < collidersCount; ii++)
541 {
542 uint cA = m_collisionArray[ii].aID;
543 uint cB = m_collisionArray[ii].bID;
544 Vector3 point = m_collisionArray[ii].point;
545 Vector3 normal = m_collisionArray[ii].normal;
546 SendCollision(cA, cB, point, normal, 0.01f);
547 SendCollision(cB, cA, point, -normal, 0.01f);
548 }
549 }
550
551 // The above SendCollision's batch up the collisions on the objects.
552 // Now push the collisions into the simulator.
553 if (ObjectsWithCollisions.Count > 0)
554 {
555 foreach (BSPhysObject bsp in ObjectsWithCollisions)
556 if (!bsp.SendCollisions())
557 {
558 // If the object is done colliding, see that it's removed from the colliding list
559 ObjectsWithNoMoreCollisions.Add(bsp);
560 }
561 }
562
563 // This is a kludge to get avatar movement updates.
564 // The simulator expects collisions for avatars even if there are have been no collisions.
565 // The event updates avatar animations and stuff.
566 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
567 foreach (BSPhysObject bsp in m_avatars)
568 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
569 bsp.SendCollisions();
570
571 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
572 // Not done above because it is inside an iteration of ObjectWithCollisions.
573 // This complex collision processing is required to create an empty collision
574 // event call after all real collisions have happened on an object. This enables
575 // the simulator to generate the 'collision end' event.
576 if (ObjectsWithNoMoreCollisions.Count > 0)
577 {
578 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
579 ObjectsWithCollisions.Remove(po);
580 ObjectsWithNoMoreCollisions.Clear();
581 }
582 // Done with collisions.
583
584 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
585 if (updatedEntityCount > 0)
586 {
587 for (int ii = 0; ii < updatedEntityCount; ii++)
588 {
589 EntityProperties entprop = m_updateArray[ii];
590 BSPhysObject pobj;
591 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
592 {
593 pobj.UpdateProperties(entprop);
594 }
595 }
596 }
597
598 TriggerPostStepEvent(timeStep);
599
600 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
601 // Only enable this in a limited test world with few objects.
602 if (m_physicsPhysicalDumpEnabled)
603 PE.DumpAllInfo(World);
604
605 // The physics engine returns the number of milliseconds it simulated this call.
606 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
607 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
608 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
609 }
610
611 // Something has collided
612 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
613 {
614 if (localID <= TerrainManager.HighestTerrainID)
615 {
616 return; // don't send collisions to the terrain
617 }
618
619 BSPhysObject collider;
620 if (!PhysObjects.TryGetValue(localID, out collider))
621 {
622 // If the object that is colliding cannot be found, just ignore the collision.
623 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
624 return;
625 }
626
627 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
628 BSPhysObject collidee = null;
629 PhysObjects.TryGetValue(collidingWith, out collidee);
630
631 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
632
633 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
634 {
635 // If a collision was posted, remember to send it to the simulator
636 ObjectsWithCollisions.Add(collider);
637 }
638
639 return;
640 }
641
642 #endregion // Simulation
643
644 public override void GetResults() { }
645
646 #region Terrain
647
648 public override void SetTerrain(float[] heightMap) {
649 TerrainManager.SetTerrain(heightMap);
650 }
651
652 public override void SetWaterLevel(float baseheight)
653 {
654 SimpleWaterLevel = baseheight;
655 }
656
657 public override void DeleteTerrain()
658 {
659 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
660 }
661
662 // Although no one seems to check this, I do support combining.
663 public override bool SupportsCombining()
664 {
665 return TerrainManager.SupportsCombining();
666 }
667 // This call says I am a child to region zero in a mega-region. 'pScene' is that
668 // of region zero, 'offset' is my offset from regions zero's origin, and
669 // 'extents' is the largest XY that is handled in my region.
670 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
671 {
672 TerrainManager.Combine(pScene, offset, extents);
673 }
674
675 // Unhook all the combining that I know about.
676 public override void UnCombine(PhysicsScene pScene)
677 {
678 TerrainManager.UnCombine(pScene);
679 }
680
681 #endregion // Terrain
682
683 public override Dictionary<uint, float> GetTopColliders()
684 {
685 return new Dictionary<uint, float>();
686 }
687
688 public override bool IsThreaded { get { return false; } }
689
690 #region Taints
691 // The simulation execution order is:
692 // Simulate()
693 // DoOneTimeTaints
694 // TriggerPreStepEvent
695 // DoOneTimeTaints
696 // Step()
697 // ProcessAndForwardCollisions
698 // ProcessAndForwardPropertyUpdates
699 // TriggerPostStepEvent
700
701 // Calls to the PhysicsActors can't directly call into the physics engine
702 // because it might be busy. We delay changes to a known time.
703 // We rely on C#'s closure to save and restore the context for the delegate.
704 public void TaintedObject(String ident, TaintCallback callback)
705 {
706 if (!m_initialized) return;
707
708 lock (_taintLock)
709 {
710 _taintOperations.Add(new TaintCallbackEntry(ident, callback));
711 }
712
713 return;
714 }
715
716 // Sometimes a potentially tainted operation can be used in and out of taint time.
717 // This routine executes the command immediately if in taint-time otherwise it is queued.
718 public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
719 {
720 if (inTaintTime)
721 callback();
722 else
723 TaintedObject(ident, callback);
724 }
725
726 private void TriggerPreStepEvent(float timeStep)
727 {
728 PreStepAction actions = BeforeStep;
729 if (actions != null)
730 actions(timeStep);
731
732 }
733
734 private void TriggerPostStepEvent(float timeStep)
735 {
736 PreStepAction actions = AfterStep;
737 if (actions != null)
738 actions(timeStep);
739
740 }
741
742 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
743 // a callback into itself to do the actual property change. That callback is called
744 // here just before the physics engine is called to step the simulation.
745 public void ProcessTaints()
746 {
747 ProcessRegularTaints();
748 ProcessPostTaintTaints();
749 }
750
751 private void ProcessRegularTaints()
752 {
753 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
754 {
755 // swizzle a new list into the list location so we can process what's there
756 List<TaintCallbackEntry> oldList;
757 lock (_taintLock)
758 {
759 oldList = _taintOperations;
760 _taintOperations = new List<TaintCallbackEntry>();
761 }
762
763 foreach (TaintCallbackEntry tcbe in oldList)
764 {
765 try
766 {
767 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
768 tcbe.callback();
769 }
770 catch (Exception e)
771 {
772 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
773 }
774 }
775 oldList.Clear();
776 }
777 }
778
779 // Schedule an update to happen after all the regular taints are processed.
780 // Note that new requests for the same operation ("ident") for the same object ("ID")
781 // will replace any previous operation by the same object.
782 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
783 {
784 string uniqueIdent = ident + "-" + ID.ToString();
785 lock (_taintLock)
786 {
787 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback);
788 }
789
790 return;
791 }
792
793 // Taints that happen after the normal taint processing but before the simulation step.
794 private void ProcessPostTaintTaints()
795 {
796 if (_postTaintOperations.Count > 0)
797 {
798 Dictionary<string, TaintCallbackEntry> oldList;
799 lock (_taintLock)
800 {
801 oldList = _postTaintOperations;
802 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
803 }
804
805 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
806 {
807 try
808 {
809 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
810 kvp.Value.callback();
811 }
812 catch (Exception e)
813 {
814 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
815 }
816 }
817 oldList.Clear();
818 }
819 }
820
821 // Only used for debugging. Does not change state of anything so locking is not necessary.
822 public bool AssertInTaintTime(string whereFrom)
823 {
824 if (!InTaintTime)
825 {
826 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
827 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
828 Util.PrintCallStack(DetailLog);
829 }
830 return InTaintTime;
831 }
832
833 #endregion // Taints
834
835 #region INI and command line parameter processing
836
837 #region IPhysicsParameters
838 // Get the list of parameters this physics engine supports
839 public PhysParameterEntry[] GetParameterList()
840 {
841 BSParam.BuildParameterTable();
842 return BSParam.SettableParameters;
843 }
844
845 // Set parameter on a specific or all instances.
846 // Return 'false' if not able to set the parameter.
847 // Setting the value in the m_params block will change the value the physics engine
848 // will use the next time since it's pinned and shared memory.
849 // Some of the values require calling into the physics engine to get the new
850 // value activated ('terrainFriction' for instance).
851 public bool SetPhysicsParameter(string parm, float val, uint localID)
852 {
853 bool ret = false;
854 BSParam.ParameterDefn theParam;
855 if (BSParam.TryGetParameter(parm, out theParam))
856 {
857 theParam.setter(this, parm, localID, val);
858 ret = true;
859 }
860 return ret;
861 }
862
863 // update all the localIDs specified
864 // If the local ID is APPLY_TO_NONE, just change the default value
865 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
866 // If the localID is a specific object, apply the parameter change to only that object
867 internal delegate void AssignVal(float x);
868 internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
869 {
870 List<uint> objectIDs = new List<uint>();
871 switch (localID)
872 {
873 case PhysParameterEntry.APPLY_TO_NONE:
874 setDefault(val); // setting only the default value
875 // This will cause a call into the physical world if some operation is specified (SetOnObject).
876 objectIDs.Add(TERRAIN_ID);
877 TaintedUpdateParameter(parm, objectIDs, val);
878 break;
879 case PhysParameterEntry.APPLY_TO_ALL:
880 setDefault(val); // setting ALL also sets the default value
881 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
882 TaintedUpdateParameter(parm, objectIDs, val);
883 break;
884 default:
885 // setting only one localID
886 objectIDs.Add(localID);
887 TaintedUpdateParameter(parm, objectIDs, val);
888 break;
889 }
890 }
891
892 // schedule the actual updating of the paramter to when the phys engine is not busy
893 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
894 {
895 float xval = val;
896 List<uint> xlIDs = lIDs;
897 string xparm = parm;
898 TaintedObject("BSScene.UpdateParameterSet", delegate() {
899 BSParam.ParameterDefn thisParam;
900 if (BSParam.TryGetParameter(xparm, out thisParam))
901 {
902 if (thisParam.onObject != null)
903 {
904 foreach (uint lID in xlIDs)
905 {
906 BSPhysObject theObject = null;
907 PhysObjects.TryGetValue(lID, out theObject);
908 thisParam.onObject(this, theObject, xval);
909 }
910 }
911 }
912 });
913 }
914
915 // Get parameter.
916 // Return 'false' if not able to get the parameter.
917 public bool GetPhysicsParameter(string parm, out float value)
918 {
919 float val = 0f;
920 bool ret = false;
921 BSParam.ParameterDefn theParam;
922 if (BSParam.TryGetParameter(parm, out theParam))
923 {
924 val = theParam.getter(this);
925 ret = true;
926 }
927 value = val;
928 return ret;
929 }
930
931 #endregion IPhysicsParameters
932
933 #endregion Runtime settable parameters
934
935 // Invoke the detailed logger and output something if it's enabled.
936 public void DetailLog(string msg, params Object[] args)
937 {
938 PhysicsLogging.Write(msg, args);
939 // Add the Flush() if debugging crashes. Gets all the messages written out.
940 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
941 }
942 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
943 public const string DetailLogZero = "0000000000";
944
945}
946}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
deleted file mode 100755
index d361f18..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ /dev/null
@@ -1,1009 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.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 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40
41 private BSScene PhysicsScene { get; set; }
42
43 private Object m_collectionActivityLock = new Object();
44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public BulletShape shape;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public BulletShape shape;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 private bool DDetail = false;
69
70 public BSShapeCollection(BSScene physScene)
71 {
72 PhysicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging
76 // statements can be commented/removed.
77 DDetail = true;
78 }
79
80 public void Dispose()
81 {
82 // TODO!!!!!!!!!
83 }
84
85 // Callbacks called just before either the body or shape is destroyed.
86 // Mostly used for changing bodies out from under Linksets.
87 // Useful for other cases where parameters need saving.
88 // Passing 'null' says no callback.
89 public delegate void ShapeDestructionCallback(BulletShape shape);
90 public delegate void BodyDestructionCallback(BulletBody body);
91
92 // Called to update/change the body and shape for an object.
93 // First checks the shape and updates that if necessary then makes
94 // sure the body is of the right type.
95 // Return 'true' if either the body or the shape changed.
96 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
97 // the current shape or body is destroyed. This allows the caller to remove any
98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
99 // remove the physical constraints before the body is destroyed.
100 // Called at taint-time!!
101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
103 {
104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
105
106 bool ret = false;
107
108 // This lock could probably be pushed down lower but building shouldn't take long
109 lock (m_collectionActivityLock)
110 {
111 // Do we have the correct geometry for this type of object?
112 // Updates prim.BSShape with information/pointers to shape.
113 // Returns 'true' of BSShape is changed to a new shape.
114 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
115 // If we had to select a new shape geometry for the object,
116 // rebuild the body around it.
117 // Updates prim.BSBody with information/pointers to requested body
118 // Returns 'true' if BSBody was changed.
119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
120 prim.PhysShape, bodyCallback);
121 ret = newGeom || newBody;
122 }
123 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
124 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
125
126 return ret;
127 }
128
129 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
130 {
131 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
132 }
133
134 // Track another user of a body.
135 // We presume the caller has allocated the body.
136 // Bodies only have one user so the body is just put into the world if not already there.
137 public void ReferenceBody(BulletBody body, bool inTaintTime)
138 {
139 lock (m_collectionActivityLock)
140 {
141 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
142 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
143 {
144 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
145 {
146 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
147 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
148 }
149 });
150 }
151 }
152
153 // Release the usage of a body.
154 // Called when releasing use of a BSBody. BSShape is handled separately.
155 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
156 {
157 if (!body.HasPhysicalBody)
158 return;
159
160 lock (m_collectionActivityLock)
161 {
162 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
163 {
164 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
165 body.ID, body, inTaintTime);
166 // If the caller needs to know the old body is going away, pass the event up.
167 if (bodyCallback != null) bodyCallback(body);
168
169 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
170 {
171 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
172 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
173 }
174
175 // Zero any reference to the shape so it is not freed when the body is deleted.
176 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
177 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
178 });
179 }
180 }
181
182 // Track the datastructures and use count for a shape.
183 // When creating a hull, this is called first to reference the mesh
184 // and then again to reference the hull.
185 // Meshes and hulls for the same shape have the same hash key.
186 // NOTE that native shapes are not added to the mesh list or removed.
187 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
188 public bool ReferenceShape(BulletShape shape)
189 {
190 bool ret = false;
191 switch (shape.type)
192 {
193 case BSPhysicsShapeType.SHAPE_MESH:
194 MeshDesc meshDesc;
195 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
196 {
197 // There is an existing instance of this mesh.
198 meshDesc.referenceCount++;
199 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
200 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
201 }
202 else
203 {
204 // This is a new reference to a mesh
205 meshDesc.shape = shape.Clone();
206 meshDesc.shapeKey = shape.shapeKey;
207 // We keep a reference to the underlying IMesh data so a hull can be built
208 meshDesc.referenceCount = 1;
209 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
210 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
211 ret = true;
212 }
213 meshDesc.lastReferenced = System.DateTime.Now;
214 Meshes[shape.shapeKey] = meshDesc;
215 break;
216 case BSPhysicsShapeType.SHAPE_HULL:
217 HullDesc hullDesc;
218 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
219 {
220 // There is an existing instance of this hull.
221 hullDesc.referenceCount++;
222 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
223 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
224 }
225 else
226 {
227 // This is a new reference to a hull
228 hullDesc.shape = shape.Clone();
229 hullDesc.shapeKey = shape.shapeKey;
230 hullDesc.referenceCount = 1;
231 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
232 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
233 ret = true;
234
235 }
236 hullDesc.lastReferenced = System.DateTime.Now;
237 Hulls[shape.shapeKey] = hullDesc;
238 break;
239 case BSPhysicsShapeType.SHAPE_UNKNOWN:
240 break;
241 default:
242 // Native shapes are not tracked and they don't go into any list
243 break;
244 }
245 return ret;
246 }
247
248 // Release the usage of a shape.
249 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
250 {
251 if (!shape.HasPhysicalShape)
252 return;
253
254 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
255 {
256 if (shape.HasPhysicalShape)
257 {
258 if (shape.isNativeShape)
259 {
260 // Native shapes are not tracked and are released immediately
261 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
262 BSScene.DetailLogZero, shape.AddrString, inTaintTime);
263 if (shapeCallback != null) shapeCallback(shape);
264 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
265 }
266 else
267 {
268 switch (shape.type)
269 {
270 case BSPhysicsShapeType.SHAPE_HULL:
271 DereferenceHull(shape, shapeCallback);
272 break;
273 case BSPhysicsShapeType.SHAPE_MESH:
274 DereferenceMesh(shape, shapeCallback);
275 break;
276 case BSPhysicsShapeType.SHAPE_COMPOUND:
277 DereferenceCompound(shape, shapeCallback);
278 break;
279 case BSPhysicsShapeType.SHAPE_UNKNOWN:
280 break;
281 default:
282 break;
283 }
284 }
285 }
286 });
287 }
288
289 // Count down the reference count for a mesh shape
290 // Called at taint-time.
291 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
292 {
293 MeshDesc meshDesc;
294 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
295 {
296 meshDesc.referenceCount--;
297 // TODO: release the Bullet storage
298 if (shapeCallback != null) shapeCallback(shape);
299 meshDesc.lastReferenced = System.DateTime.Now;
300 Meshes[shape.shapeKey] = meshDesc;
301 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
302 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
303
304 }
305 }
306
307 // Count down the reference count for a hull shape
308 // Called at taint-time.
309 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
310 {
311 HullDesc hullDesc;
312 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
313 {
314 hullDesc.referenceCount--;
315 // TODO: release the Bullet storage (aging old entries?)
316
317 // Tell upper layers that, if they have dependencies on this shape, this link is going away
318 if (shapeCallback != null) shapeCallback(shape);
319
320 hullDesc.lastReferenced = System.DateTime.Now;
321 Hulls[shape.shapeKey] = hullDesc;
322 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
323 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
324 }
325 }
326
327 // Remove a reference to a compound shape.
328 // Taking a compound shape apart is a little tricky because if you just delete the
329 // physical shape, it will free all the underlying children. We can't do that because
330 // they could be shared. So, this removes each of the children from the compound and
331 // dereferences them separately before destroying the compound collision object itself.
332 // Called at taint-time.
333 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
334 {
335 if (!PhysicsScene.PE.IsCompound(shape))
336 {
337 // Failed the sanity check!!
338 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
339 LogHeader, shape.type, shape.AddrString);
340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
341 BSScene.DetailLogZero, shape.type, shape.AddrString);
342 return;
343 }
344
345 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
346 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
347
348 for (int ii = numChildren - 1; ii >= 0; ii--)
349 {
350 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
351 DereferenceAnonCollisionShape(childShape);
352 }
353 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
354 }
355
356 // Sometimes we have a pointer to a collision shape but don't know what type it is.
357 // Figure out type and call the correct dereference routine.
358 // Called at taint-time.
359 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
360 {
361 MeshDesc meshDesc;
362 HullDesc hullDesc;
363
364 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
365 {
366 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
367 shapeInfo.shapeKey = meshDesc.shapeKey;
368 }
369 else
370 {
371 if (TryGetHullByPtr(shapeInfo, out hullDesc))
372 {
373 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
374 shapeInfo.shapeKey = hullDesc.shapeKey;
375 }
376 else
377 {
378 if (PhysicsScene.PE.IsCompound(shapeInfo))
379 {
380 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
381 }
382 else
383 {
384 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
385 {
386 shapeInfo.isNativeShape = true;
387 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
388 }
389 }
390 }
391 }
392
393 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
394
395 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
396 {
397 DereferenceShape(shapeInfo, true, null);
398 }
399 else
400 {
401 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
402 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
403 }
404 }
405
406 // Create the geometry information in Bullet for later use.
407 // The objects needs a hull if it's physical otherwise a mesh is enough.
408 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
409 // shared geometries will be used. If the parameters of the existing shape are the same
410 // as this request, the shape is not rebuilt.
411 // Info in prim.BSShape is updated to the new shape.
412 // Returns 'true' if the geometry was rebuilt.
413 // Called at taint-time!
414 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
415 {
416 bool ret = false;
417 bool haveShape = false;
418
419 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
420 {
421 // an avatar capsule is close to a native shape (it is not shared)
422 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
423 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
424 ret = true;
425 haveShape = true;
426 }
427
428 // Compound shapes are handled special as they are rebuilt from scratch.
429 // This isn't too great a hardship since most of the child shapes will have already been created.
430 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
431 {
432 ret = GetReferenceToCompoundShape(prim, shapeCallback);
433 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
434 haveShape = true;
435 }
436
437 if (!haveShape)
438 {
439 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
440 }
441
442 return ret;
443 }
444
445 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
446 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
447 {
448 bool ret = false;
449 bool haveShape = false;
450 bool nativeShapePossible = true;
451 PrimitiveBaseShape pbs = prim.BaseShape;
452
453 // If the prim attributes are simple, this could be a simple Bullet native shape
454 if (!haveShape
455 && pbs != null
456 && nativeShapePossible
457 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
458 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
459 && pbs.ProfileHollow == 0
460 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
461 && pbs.PathBegin == 0 && pbs.PathEnd == 0
462 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
463 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
464 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
465 {
466 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
467 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
468 if (prim.PhysShape.HasPhysicalShape)
469 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
470
471 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
472 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
473
474 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
475 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
476 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
477 {
478 haveShape = true;
479 if (forceRebuild
480 || prim.Scale != scaleOfExistingShape
481 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
482 )
483 {
484 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
485 FixedShapeKey.KEY_SPHERE, shapeCallback);
486 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
487 prim.LocalID, forceRebuild, prim.PhysShape);
488 }
489 }
490 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
491 {
492 haveShape = true;
493 if (forceRebuild
494 || prim.Scale != scaleOfExistingShape
495 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
496 )
497 {
498 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
499 FixedShapeKey.KEY_BOX, shapeCallback);
500 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
501 prim.LocalID, forceRebuild, prim.PhysShape);
502 }
503 }
504 }
505
506 // If a simple shape is not happening, create a mesh and possibly a hull.
507 if (!haveShape && pbs != null)
508 {
509 ret = CreateGeomMeshOrHull(prim, shapeCallback);
510 }
511
512 return ret;
513 }
514
515 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
516 {
517
518 bool ret = false;
519 // Note that if it's a native shape, the check for physical/non-physical is not
520 // made. Native shapes work in either case.
521 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
522 {
523 // Update prim.BSShape to reference a hull of this shape.
524 ret = GetReferenceToHull(prim,shapeCallback);
525 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
526 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
527 }
528 else
529 {
530 ret = GetReferenceToMesh(prim, shapeCallback);
531 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
532 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
533 }
534 return ret;
535 }
536
537 // Creates a native shape and assignes it to prim.BSShape.
538 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
539 private bool GetReferenceToNativeShape(BSPhysObject prim,
540 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
541 ShapeDestructionCallback shapeCallback)
542 {
543 // release any previous shape
544 DereferenceShape(prim.PhysShape, true, shapeCallback);
545
546 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
547
548 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
549 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
550 prim.LocalID, newShape, prim.Scale);
551
552 // native shapes are scaled by Bullet
553 prim.PhysShape = newShape;
554 return true;
555 }
556
557 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
558 FixedShapeKey shapeKey)
559 {
560 BulletShape newShape;
561 // Need to make sure the passed shape information is for the native type.
562 ShapeData nativeShapeData = new ShapeData();
563 nativeShapeData.Type = shapeType;
564 nativeShapeData.ID = prim.LocalID;
565 nativeShapeData.Scale = prim.Scale;
566 nativeShapeData.Size = prim.Scale; // unneeded, I think.
567 nativeShapeData.MeshKey = (ulong)shapeKey;
568 nativeShapeData.HullKey = (ulong)shapeKey;
569
570 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
571 {
572
573 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
574 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
575 }
576 else
577 {
578 // Native shapes are scaled in Bullet so set the scaling to the size
579 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
580
581 }
582 if (!newShape.HasPhysicalShape)
583 {
584 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
585 LogHeader, prim.LocalID, shapeType);
586 }
587 newShape.shapeKey = (System.UInt64)shapeKey;
588 newShape.isNativeShape = true;
589
590 return newShape;
591 }
592
593 // Builds a mesh shape in the physical world and updates prim.BSShape.
594 // Dereferences previous shape in BSShape and adds a reference for this new shape.
595 // Returns 'true' of a mesh was actually built. Otherwise .
596 // Called at taint-time!
597 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
598 {
599 BulletShape newShape = new BulletShape();
600
601 float lod;
602 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
603
604 // if this new shape is the same as last time, don't recreate the mesh
605 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
606 return false;
607
608 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
609 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
610
611 // Since we're recreating new, get rid of the reference to the previous shape
612 DereferenceShape(prim.PhysShape, true, shapeCallback);
613
614 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
615 // Take evasive action if the mesh was not constructed.
616 newShape = VerifyMeshCreated(newShape, prim);
617
618 ReferenceShape(newShape);
619
620 prim.PhysShape = newShape;
621
622 return true; // 'true' means a new shape has been added to this prim
623 }
624
625 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
626 {
627 BulletShape newShape = new BulletShape();
628 IMesh meshData = null;
629
630 MeshDesc meshDesc;
631 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
632 {
633 // If the mesh has already been built just use it.
634 newShape = meshDesc.shape.Clone();
635 }
636 else
637 {
638 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
639
640 if (meshData != null)
641 {
642 int[] indices = meshData.getIndexListAsInt();
643 List<OMV.Vector3> vertices = meshData.getVertexList();
644
645 float[] verticesAsFloats = new float[vertices.Count * 3];
646 int vi = 0;
647 foreach (OMV.Vector3 vv in vertices)
648 {
649 verticesAsFloats[vi++] = vv.X;
650 verticesAsFloats[vi++] = vv.Y;
651 verticesAsFloats[vi++] = vv.Z;
652 }
653
654 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
655 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
656
657 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
658 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
659 }
660 }
661 newShape.shapeKey = newMeshKey;
662
663 return newShape;
664 }
665
666 // See that hull shape exists in the physical world and update prim.BSShape.
667 // We could be creating the hull because scale changed or whatever.
668 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
669 {
670 BulletShape newShape;
671
672 float lod;
673 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
674
675 // if the hull hasn't changed, don't rebuild it
676 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
677 return false;
678
679 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
680 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
681
682 // Remove usage of the previous shape.
683 DereferenceShape(prim.PhysShape, true, shapeCallback);
684
685 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
686 newShape = VerifyMeshCreated(newShape, prim);
687
688 ReferenceShape(newShape);
689
690 prim.PhysShape = newShape;
691 return true; // 'true' means a new shape has been added to this prim
692 }
693
694 List<ConvexResult> m_hulls;
695 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
696 {
697
698 BulletShape newShape = new BulletShape();
699 IntPtr hullPtr = IntPtr.Zero;
700
701 HullDesc hullDesc;
702 if (Hulls.TryGetValue(newHullKey, out hullDesc))
703 {
704 // If the hull shape already is created, just use it.
705 newShape = hullDesc.shape.Clone();
706 }
707 else
708 {
709 // Build a new hull in the physical world
710 // Pass true for physicalness as this creates some sort of bounding box which we don't need
711 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
712 if (meshData != null)
713 {
714
715 int[] indices = meshData.getIndexListAsInt();
716 List<OMV.Vector3> vertices = meshData.getVertexList();
717
718 //format conversion from IMesh format to DecompDesc format
719 List<int> convIndices = new List<int>();
720 List<float3> convVertices = new List<float3>();
721 for (int ii = 0; ii < indices.GetLength(0); ii++)
722 {
723 convIndices.Add(indices[ii]);
724 }
725 foreach (OMV.Vector3 vv in vertices)
726 {
727 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
728 }
729
730 // setup and do convex hull conversion
731 m_hulls = new List<ConvexResult>();
732 DecompDesc dcomp = new DecompDesc();
733 dcomp.mIndices = convIndices;
734 dcomp.mVertices = convVertices;
735 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
736 // create the hull into the _hulls variable
737 convexBuilder.process(dcomp);
738
739 // Convert the vertices and indices for passing to unmanaged.
740 // The hull information is passed as a large floating point array.
741 // The format is:
742 // convHulls[0] = number of hulls
743 // convHulls[1] = number of vertices in first hull
744 // convHulls[2] = hull centroid X coordinate
745 // convHulls[3] = hull centroid Y coordinate
746 // convHulls[4] = hull centroid Z coordinate
747 // convHulls[5] = first hull vertex X
748 // convHulls[6] = first hull vertex Y
749 // convHulls[7] = first hull vertex Z
750 // convHulls[8] = second hull vertex X
751 // ...
752 // convHulls[n] = number of vertices in second hull
753 // convHulls[n+1] = second hull centroid X coordinate
754 // ...
755 //
756 // TODO: is is very inefficient. Someday change the convex hull generator to return
757 // data structures that do not need to be converted in order to pass to Bullet.
758 // And maybe put the values directly into pinned memory rather than marshaling.
759 int hullCount = m_hulls.Count;
760 int totalVertices = 1; // include one for the count of the hulls
761 foreach (ConvexResult cr in m_hulls)
762 {
763 totalVertices += 4; // add four for the vertex count and centroid
764 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
765 }
766 float[] convHulls = new float[totalVertices];
767
768 convHulls[0] = (float)hullCount;
769 int jj = 1;
770 foreach (ConvexResult cr in m_hulls)
771 {
772 // copy vertices for index access
773 float3[] verts = new float3[cr.HullVertices.Count];
774 int kk = 0;
775 foreach (float3 ff in cr.HullVertices)
776 {
777 verts[kk++] = ff;
778 }
779
780 // add to the array one hull's worth of data
781 convHulls[jj++] = cr.HullIndices.Count;
782 convHulls[jj++] = 0f; // centroid x,y,z
783 convHulls[jj++] = 0f;
784 convHulls[jj++] = 0f;
785 foreach (int ind in cr.HullIndices)
786 {
787 convHulls[jj++] = verts[ind].x;
788 convHulls[jj++] = verts[ind].y;
789 convHulls[jj++] = verts[ind].z;
790 }
791 }
792 // create the hull data structure in Bullet
793 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
794 }
795 }
796
797 newShape.shapeKey = newHullKey;
798
799 return newShape;
800 }
801
802 // Callback from convex hull creater with a newly created hull.
803 // Just add it to our collection of hulls for this shape.
804 private void HullReturn(ConvexResult result)
805 {
806 m_hulls.Add(result);
807 return;
808 }
809
810 // Compound shapes are always built from scratch.
811 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
812 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
813 {
814 // Remove reference to the old shape
815 // Don't need to do this as the shape is freed when the new root shape is created below.
816 // DereferenceShape(prim.PhysShape, true, shapeCallback);
817
818
819 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
820
821 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
822 CreateGeomMeshOrHull(prim, shapeCallback);
823 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
824 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
825 prim.LocalID, cShape, prim.PhysShape);
826
827 prim.PhysShape = cShape;
828
829 return true;
830 }
831
832 // Create a hash of all the shape parameters to be used as a key
833 // for this particular shape.
834 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
835 {
836 // level of detail based on size and type of the object
837 float lod = BSParam.MeshLOD;
838 if (pbs.SculptEntry)
839 lod = BSParam.SculptLOD;
840
841 // Mega prims usually get more detail because one can interact with shape approximations at this size.
842 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
843 if (maxAxis > BSParam.MeshMegaPrimThreshold)
844 lod = BSParam.MeshMegaPrimLOD;
845
846 retLod = lod;
847 return pbs.GetMeshKey(size, lod);
848 }
849 // For those who don't want the LOD
850 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
851 {
852 float lod;
853 return ComputeShapeKey(size, pbs, out lod);
854 }
855
856 // The creation of a mesh or hull can fail if an underlying asset is not available.
857 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
858 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
859 // The first case causes the asset to be fetched. The second case requires
860 // us to not loop forever.
861 // Called after creating a physical mesh or hull. If the physical shape was created,
862 // just return.
863 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
864 {
865 // If the shape was successfully created, nothing more to do
866 if (newShape.HasPhysicalShape)
867 return newShape;
868
869 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
870 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
871 {
872 prim.LastAssetBuildFailed = true;
873 BSPhysObject xprim = prim;
874 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
875 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
876 Util.FireAndForget(delegate
877 {
878 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
879 if (assetProvider != null)
880 {
881 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
882 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
883 {
884 if (!yprim.BaseShape.SculptEntry)
885 return;
886 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
887 return;
888
889 yprim.BaseShape.SculptData = asset.Data;
890 // This will cause the prim to see that the filler shape is not the right
891 // one and try again to build the object.
892 // No race condition with the normal shape setting since the rebuild is at taint time.
893 yprim.ForceBodyShapeRebuild(false);
894
895 });
896 }
897 });
898 }
899 else
900 {
901 if (prim.LastAssetBuildFailed)
902 {
903 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
904 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
905 }
906 }
907
908 // While we figure out the real problem, stick a simple native shape on the object.
909 BulletShape fillinShape =
910 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
911
912 return fillinShape;
913 }
914
915 // Create a body object in Bullet.
916 // Updates prim.BSBody with the information about the new body if one is created.
917 // Returns 'true' if an object was actually created.
918 // Called at taint-time.
919 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape,
920 BodyDestructionCallback bodyCallback)
921 {
922 bool ret = false;
923
924 // the mesh, hull or native shape must have already been created in Bullet
925 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
926
927 // If there is an existing body, verify it's of an acceptable type.
928 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
929 if (!mustRebuild)
930 {
931 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
932 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
933 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
934 {
935 // If the collisionObject is not the correct type for solidness, rebuild what's there
936 mustRebuild = true;
937 }
938 }
939
940 if (mustRebuild || forceRebuild)
941 {
942 // Free any old body
943 DereferenceBody(prim.PhysBody, true, bodyCallback);
944
945 BulletBody aBody;
946 if (prim.IsSolid)
947 {
948 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
949 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody);
950 }
951 else
952 {
953 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
954 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
955 }
956
957 ReferenceBody(aBody, true);
958
959 prim.PhysBody = aBody;
960
961 ret = true;
962 }
963
964 return ret;
965 }
966
967 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
968 {
969 bool ret = false;
970 MeshDesc foundDesc = new MeshDesc();
971 foreach (MeshDesc md in Meshes.Values)
972 {
973 if (md.shape.ReferenceSame(shape))
974 {
975 foundDesc = md;
976 ret = true;
977 break;
978 }
979
980 }
981 outDesc = foundDesc;
982 return ret;
983 }
984
985 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
986 {
987 bool ret = false;
988 HullDesc foundDesc = new HullDesc();
989 foreach (HullDesc hd in Hulls.Values)
990 {
991 if (hd.shape.ReferenceSame(shape))
992 {
993 foundDesc = hd;
994 ret = true;
995 break;
996 }
997
998 }
999 outDesc = foundDesc;
1000 return ret;
1001 }
1002
1003 private void DetailLog(string msg, params Object[] args)
1004 {
1005 if (PhysicsScene.PhysicsLogging.Enabled)
1006 PhysicsScene.DetailLog(msg, args);
1007 }
1008}
1009}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
deleted file mode 100755
index c75eb9b..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ /dev/null
@@ -1,232 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public abstract class BSShape
36{
37 public IntPtr ptr { get; set; }
38 public BSPhysicsShapeType type { get; set; }
39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; }
42
43 public BSShape()
44 {
45 ptr = IntPtr.Zero;
46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0;
48 referenceCount = 0;
49 lastReferenced = DateTime.Now;
50 }
51
52 // Get a reference to a physical shape. Create if it doesn't exist
53 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
54 {
55 BSShape ret = null;
56
57 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
58 {
59 // an avatar capsule is close to a native shape (it is not shared)
60 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
61 FixedShapeKey.KEY_CAPSULE);
62 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
63 }
64
65 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created.
67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
70 ret = BSShapeCompound.GetReference(prim);
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 }
73
74 if (ret == null)
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
76
77 return ret;
78 }
79 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
80 {
81 return null;
82 }
83 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
84 {
85 return null;
86 }
87
88 // Release the use of a physical shape.
89 public abstract void Dereference(BSScene physicsScene);
90
91 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference();
93
94 // Returns a string for debugging that uniquily identifies the memory used by this instance
95 public string AddrString
96 {
97 get { return ptr.ToString("X"); }
98 }
99
100 public override string ToString()
101 {
102 StringBuilder buff = new StringBuilder();
103 buff.Append("<p=");
104 buff.Append(AddrString);
105 buff.Append(",s=");
106 buff.Append(type.ToString());
107 buff.Append(",k=");
108 buff.Append(key.ToString("X"));
109 buff.Append(",c=");
110 buff.Append(referenceCount.ToString());
111 buff.Append(">");
112 return buff.ToString();
113 }
114}
115
116public class BSShapeNull : BSShape
117{
118 public BSShapeNull() : base()
119 {
120 }
121 public static BSShape GetReference() { return new BSShapeNull(); }
122 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
123}
124
125public class BSShapeNative : BSShape
126{
127 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
128 public BSShapeNative() : base()
129 {
130 }
131 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
132 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
133 {
134 // Native shapes are not shared and are always built anew.
135 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
136 return null;
137 }
138
139 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
140 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
141 {
142 ShapeData nativeShapeData = new ShapeData();
143 nativeShapeData.Type = shapeType;
144 nativeShapeData.ID = prim.LocalID;
145 nativeShapeData.Scale = prim.Scale;
146 nativeShapeData.Size = prim.Scale;
147 nativeShapeData.MeshKey = (ulong)shapeKey;
148 nativeShapeData.HullKey = (ulong)shapeKey;
149
150
151 /*
152 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
153 {
154 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
155 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
156 }
157 else
158 {
159 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
160 }
161 if (ptr == IntPtr.Zero)
162 {
163 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
164 LogHeader, prim.LocalID, shapeType);
165 }
166 type = shapeType;
167 key = (UInt64)shapeKey;
168 */
169 }
170 // Make this reference to the physical shape go away since native shapes are not shared.
171 public override void Dereference(BSScene physicsScene)
172 {
173 /*
174 // Native shapes are not tracked and are released immediately
175 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
176 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
177 ptr = IntPtr.Zero;
178 // Garbage collection will free up this instance.
179 */
180 }
181}
182
183public class BSShapeMesh : BSShape
184{
185 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
186 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
187
188 public BSShapeMesh() : base()
189 {
190 }
191 public static BSShape GetReference() { return new BSShapeNull(); }
192 public override void Dereference(BSScene physicsScene) { }
193}
194
195public class BSShapeHull : BSShape
196{
197 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
198 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
199
200 public BSShapeHull() : base()
201 {
202 }
203 public static BSShape GetReference() { return new BSShapeNull(); }
204 public override void Dereference(BSScene physicsScene) { }
205}
206
207public class BSShapeCompound : BSShape
208{
209 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
210 public BSShapeCompound() : base()
211 {
212 }
213 public static BSShape GetReference(BSPhysObject prim)
214 {
215 return new BSShapeNull();
216 }
217 public override void Dereference(BSScene physicsScene) { }
218}
219
220public class BSShapeAvatar : BSShape
221{
222 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
223 public BSShapeAvatar() : base()
224 {
225 }
226 public static BSShape GetReference(BSPhysObject prim)
227 {
228 return new BSShapeNull();
229 }
230 public override void Dereference(BSScene physicsScene) { }
231}
232}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
deleted file mode 100755
index 1d55ce3..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ /dev/null
@@ -1,265 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.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 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
80 m_sizeX, m_sizeY,
81 (float)m_sizeX, (float)m_sizeY,
82 Vector3.Zero, 1.0f,
83 out indicesCount, out indices, out verticesCount, out vertices))
84 {
85 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
87 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
88 // Something is very messed up and a crash is in our future.
89 return;
90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
93
94 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
95 if (!m_terrainShape.HasPhysicalShape)
96 {
97 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
99 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
100 // Something is very messed up and a crash is in our future.
101 return;
102 }
103
104 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity;
106
107 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
108 if (!m_terrainBody.HasPhysicalBody)
109 {
110 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
112 // Something is very messed up and a crash is in our future.
113 return;
114 }
115
116 // Set current terrain attributes
117 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
118 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
119 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
120 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
121
122 // Static objects are not very massive.
123 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
124
125 // Put the new terrain to the world of physical objects
126 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);
127
128 // Redo its bounding box now that it is in the world
129 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);
130
131 m_terrainBody.collisionType = CollisionType.Terrain;
132 m_terrainBody.ApplyCollisionMask(PhysicsScene);
133
134 // Make it so the terrain will not move or be considered for movement.
135 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
136 }
137
138 public override void Dispose()
139 {
140 if (m_terrainBody.HasPhysicalBody)
141 {
142 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody);
143 // Frees both the body and the shape.
144 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody);
145 }
146 }
147
148 public override float GetTerrainHeightAtXYZ(Vector3 pos)
149 {
150 // For the moment use the saved heightmap to get the terrain height.
151 // TODO: raycast downward to find the true terrain below the position.
152 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
153
154 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
155 try
156 {
157 ret = m_savedHeightMap[mapIndex];
158 }
159 catch
160 {
161 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
162 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
163 LogHeader, TerrainBase, pos);
164 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
165 }
166 return ret;
167 }
168
169 // The passed position is relative to the base of the region.
170 public override float GetWaterLevelAtXYZ(Vector3 pos)
171 {
172 return PhysicsScene.SimpleWaterLevel;
173 }
174
175 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
176 // Return 'true' if successfully created.
177 public static bool ConvertHeightmapToMesh(
178 BSScene physicsScene,
179 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
180 float extentX, float extentY, // zero based range for output vertices
181 Vector3 extentBase, // base to be added to all vertices
182 float magnification, // number of vertices to create between heightMap coords
183 out int indicesCountO, out int[] indicesO,
184 out int verticesCountO, out float[] verticesO)
185 {
186 bool ret = false;
187
188 int indicesCount = 0;
189 int verticesCount = 0;
190 int[] indices = new int[0];
191 float[] vertices = new float[0];
192
193 // Simple mesh creation which assumes magnification == 1.
194 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
195
196 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
197 // from zero to <= sizeX). The triangle indices are then generated as two triangles
198 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
199 // column of vertices are used to complete the triangles of the last row and column
200 // of the heightmap.
201 try
202 {
203 // One vertice per heightmap value plus the vertices off the top and bottom edge.
204 int totalVertices = (sizeX + 1) * (sizeY + 1);
205 vertices = new float[totalVertices * 3];
206 int totalIndices = sizeX * sizeY * 6;
207 indices = new int[totalIndices];
208
209 float magX = (float)sizeX / extentX;
210 float magY = (float)sizeY / extentY;
211 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
212 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
213 float minHeight = float.MaxValue;
214 // Note that sizeX+1 vertices are created since there is land between this and the next region.
215 for (int yy = 0; yy <= sizeY; yy++)
216 {
217 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
218 {
219 int offset = yy * sizeX + xx;
220 // Extend the height with the height from the last row or column
221 if (yy == sizeY) offset -= sizeX;
222 if (xx == sizeX) offset -= 1;
223 float height = heightMap[offset];
224 minHeight = Math.Min(minHeight, height);
225 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
226 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
227 vertices[verticesCount + 2] = height + extentBase.Z;
228 verticesCount += 3;
229 }
230 }
231 verticesCount = verticesCount / 3;
232
233 for (int yy = 0; yy < sizeY; yy++)
234 {
235 for (int xx = 0; xx < sizeX; xx++)
236 {
237 int offset = yy * (sizeX + 1) + xx;
238 // Each vertices is presumed to be the upper left corner of a box of two triangles
239 indices[indicesCount + 0] = offset;
240 indices[indicesCount + 1] = offset + 1;
241 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
242 indices[indicesCount + 3] = offset + 1;
243 indices[indicesCount + 4] = offset + sizeX + 2;
244 indices[indicesCount + 5] = offset + sizeX + 1;
245 indicesCount += 6;
246 }
247 }
248
249 ret = true;
250 }
251 catch (Exception e)
252 {
253 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
254 LogHeader, physicsScene.RegionName, extentBase, e);
255 }
256
257 indicesCountO = indicesCount;
258 indicesO = indices;
259 verticesCountO = verticesCount;
260 verticesO = vertices;
261
262 return ret;
263 }
264}
265}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
index 8c6e7d6..c4a923c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
@@ -35,7 +35,7 @@ using OpenSim.Framework;
35 35
36using OpenMetaverse; 36using OpenMetaverse;
37 37
38namespace OpenSim.Region.Physics.BulletSPlugin 38namespace OpenSim.Region.PhysicsModule.BulletS
39{ 39{
40public sealed class BSAPIUnman : BSAPITemplate 40public sealed class BSAPIUnman : BSAPITemplate
41{ 41{
@@ -75,11 +75,11 @@ private sealed class BulletBodyUnman : BulletBody
75private sealed class BulletShapeUnman : BulletShape 75private sealed class BulletShapeUnman : BulletShape
76{ 76{
77 public IntPtr ptr; 77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) 78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base() 79 : base()
80 { 80 {
81 ptr = xx; 81 ptr = xx;
82 type = typ; 82 shapeType = typ;
83 } 83 }
84 public override bool HasPhysicalShape 84 public override bool HasPhysicalShape
85 { 85 {
@@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape
91 } 91 }
92 public override BulletShape Clone() 92 public override BulletShape Clone()
93 { 93 {
94 return new BulletShapeUnman(ptr, type); 94 return new BulletShapeUnman(ptr, shapeType);
95 } 95 }
96 public override bool ReferenceSame(BulletShape other) 96 public override bool ReferenceSame(BulletShape other)
97 { 97 {
@@ -166,7 +166,7 @@ public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet
166 166
167 // If Debug logging level, enable logging from the unmanaged code 167 // If Debug logging level, enable logging from the unmanaged code
168 m_DebugLogCallbackHandle = null; 168 m_DebugLogCallbackHandle = null;
169 if (BSScene.m_log.IsDebugEnabled || PhysicsScene.PhysicsLogging.Enabled) 169 if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled)
170 { 170 {
171 BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); 171 BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader);
172 if (PhysicsScene.PhysicsLogging.Enabled) 172 if (PhysicsScene.PhysicsLogging.Enabled)
@@ -202,7 +202,7 @@ private void BulletLoggerPhysLog(string msg)
202} 202}
203 203
204public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, 204public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
205 out int updatedEntityCount, out int collidersCount) 205 out int updatedEntityCount, out int collidersCount)
206{ 206{
207 BulletWorldUnman worldu = world as BulletWorldUnman; 207 BulletWorldUnman worldu = world as BulletWorldUnman;
208 return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); 208 return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount);
@@ -212,6 +212,19 @@ public override void Shutdown(BulletWorld world)
212{ 212{
213 BulletWorldUnman worldu = world as BulletWorldUnman; 213 BulletWorldUnman worldu = world as BulletWorldUnman;
214 BSAPICPP.Shutdown2(worldu.ptr); 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 }
215} 228}
216 229
217public override bool PushUpdate(BulletBody obj) 230public override bool PushUpdate(BulletBody obj)
@@ -238,23 +251,52 @@ public override BulletShape CreateMeshShape(BulletWorld world,
238 BSPhysicsShapeType.SHAPE_MESH); 251 BSPhysicsShapeType.SHAPE_MESH);
239} 252}
240 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
241public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) 264public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
242{ 265{
243 BulletWorldUnman worldu = world as BulletWorldUnman; 266 BulletWorldUnman worldu = world as BulletWorldUnman;
244 return new BulletShapeUnman( 267 return new BulletShapeUnman(
245 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), 268 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
246 BSPhysicsShapeType.SHAPE_HULL); 269 BSPhysicsShapeType.SHAPE_HULL);
247} 270}
248 271
249public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) 272public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
250{ 273{
251 BulletWorldUnman worldu = world as BulletWorldUnman; 274 BulletWorldUnman worldu = world as BulletWorldUnman;
252 BulletShapeUnman shapeu = meshShape as BulletShapeUnman; 275 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
253 return new BulletShapeUnman( 276 return new BulletShapeUnman(
254 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), 277 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms),
255 BSPhysicsShapeType.SHAPE_HULL); 278 BSPhysicsShapeType.SHAPE_HULL);
256} 279}
257 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
258public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) 300public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
259{ 301{
260 BulletWorldUnman worldu = world as BulletWorldUnman; 302 BulletWorldUnman worldu = world as BulletWorldUnman;
@@ -273,7 +315,7 @@ public override void SetShapeCollisionMargin(BulletShape shape, float margin)
273{ 315{
274 BulletShapeUnman shapeu = shape as BulletShapeUnman; 316 BulletShapeUnman shapeu = shape as BulletShapeUnman;
275 if (shapeu != null && shapeu.HasPhysicalShape) 317 if (shapeu != null && shapeu.HasPhysicalShape)
276 BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin); 318 BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
277} 319}
278 320
279public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) 321public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
@@ -327,6 +369,12 @@ public override void RemoveChildShapeFromCompoundShape(BulletShape shape, Bullet
327 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); 369 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
328} 370}
329 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
330public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) 378public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
331{ 379{
332 BulletShapeUnman shapeu = shape as BulletShapeUnman; 380 BulletShapeUnman shapeu = shape as BulletShapeUnman;
@@ -337,7 +385,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha
337{ 385{
338 BulletWorldUnman worldu = world as BulletWorldUnman; 386 BulletWorldUnman worldu = world as BulletWorldUnman;
339 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; 387 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
340 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); 388 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
341} 389}
342 390
343public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) 391public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
@@ -419,6 +467,28 @@ public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
419 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 467 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
420} 468}
421 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
422public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 492public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
423 Vector3 pivotinA, Vector3 pivotinB, 493 Vector3 pivotinA, Vector3 pivotinB,
424 Vector3 axisInA, Vector3 axisInB, 494 Vector3 axisInA, Vector3 axisInB,
@@ -431,6 +501,52 @@ public override BulletConstraint CreateHingeConstraint(BulletWorld world, Bullet
431 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 501 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
432} 502}
433 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
434public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) 550public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
435{ 551{
436 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; 552 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
@@ -480,6 +596,60 @@ public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, flo
480 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); 596 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
481} 597}
482 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
483public override bool CalculateTransforms(BulletConstraint constrain) 653public override bool CalculateTransforms(BulletConstraint constrain)
484{ 654{
485 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; 655 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
@@ -530,12 +700,12 @@ public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
530// btDynamicsWorld entries 700// btDynamicsWorld entries
531public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) 701public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
532{ 702{
533 // Bullet resets several variables when an object is added to the world.
534 // Gravity is reset to world default depending on the static/dynamic
535 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
536 BulletWorldUnman worldu = world as BulletWorldUnman; 703 BulletWorldUnman worldu = world as BulletWorldUnman;
537 BulletBodyUnman bodyu = obj as BulletBodyUnman; 704 BulletBodyUnman bodyu = obj as BulletBodyUnman;
538 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.
539 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); 709 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
540 710
541 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); 711 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
@@ -555,6 +725,13 @@ public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
555 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); 725 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
556} 726}
557 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
558public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) 735public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
559{ 736{
560 BulletWorldUnman worldu = world as BulletWorldUnman; 737 BulletWorldUnman worldu = world as BulletWorldUnman;
@@ -921,6 +1098,7 @@ public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quater
921} 1098}
922 1099
923// Add a force to the object as if its mass is one. 1100// Add a force to the object as if its mass is one.
1101// Deep down in Bullet: m_totalForce += force*m_linearFactor;
924public override void ApplyCentralForce(BulletBody obj, Vector3 force) 1102public override void ApplyCentralForce(BulletBody obj, Vector3 force)
925{ 1103{
926 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1104 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -964,6 +1142,7 @@ public override void SetSleepingThresholds(BulletBody obj, float lin_threshold,
964 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); 1142 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
965} 1143}
966 1144
1145// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
967public override void ApplyTorque(BulletBody obj, Vector3 torque) 1146public override void ApplyTorque(BulletBody obj, Vector3 torque)
968{ 1147{
969 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1148 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -971,6 +1150,8 @@ public override void ApplyTorque(BulletBody obj, Vector3 torque)
971} 1150}
972 1151
973// Apply force at the given point. Will add torque to the object. 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));
974public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) 1155public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
975{ 1156{
976 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1157 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -978,6 +1159,7 @@ public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
978} 1159}
979 1160
980// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. 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;
981public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) 1163public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
982{ 1164{
983 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1165 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -985,6 +1167,7 @@ public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
985} 1167}
986 1168
987// Apply impulse to the object's torque. Force is scaled by object's mass. 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;
988public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) 1171public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
989{ 1172{
990 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1173 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -992,6 +1175,8 @@ public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
992} 1175}
993 1176
994// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. 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));
995public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) 1180public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
996{ 1181{
997 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1182 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -1259,6 +1444,16 @@ public override void DumpPhysicsStatistics(BulletWorld world)
1259 BulletWorldUnman worldu = world as BulletWorldUnman; 1444 BulletWorldUnman worldu = world as BulletWorldUnman;
1260 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); 1445 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1261} 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}
1262 1457
1263// ===================================================================================== 1458// =====================================================================================
1264// ===================================================================================== 1459// =====================================================================================
@@ -1302,11 +1497,24 @@ public static extern IntPtr CreateMeshShape2(IntPtr world,
1302 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); 1497 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1303 1498
1304[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 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]
1305public static extern IntPtr CreateHullShape2(IntPtr world, 1505public static extern IntPtr CreateHullShape2(IntPtr world,
1306 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); 1506 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1307 1507
1308[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1309public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); 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 );
1310 1518
1311[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1519[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1312public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); 1520public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
@@ -1315,7 +1523,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
1315public static extern bool IsNativeShape2(IntPtr shape); 1523public static extern bool IsNativeShape2(IntPtr shape);
1316 1524
1317[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1318public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); 1526public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
1319 1527
1320[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1528[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1321public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 1529public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
@@ -1339,6 +1547,9 @@ public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShap
1339public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); 1547public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1340 1548
1341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 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]
1342public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); 1553public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1343 1554
1344[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1555[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1368,7 +1579,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1368public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); 1579public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1369 1580
1370[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1371public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, 1582public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1372 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, 1583 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1373 float scaleFactor, float collisionMargin); 1584 float scaleFactor, float collisionMargin);
1374 1585
@@ -1386,12 +1597,46 @@ public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr ob
1386 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 1597 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1387 1598
1388[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 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]
1389public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 1611public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1390 Vector3 pivotinA, Vector3 pivotinB, 1612 Vector3 pivotinA, Vector3 pivotinB,
1391 Vector3 axisInA, Vector3 axisInB, 1613 Vector3 axisInA, Vector3 axisInB,
1392 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 1614 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1393 1615
1394[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 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]
1395public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); 1640public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1396 1641
1397[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1417,6 +1662,33 @@ public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enabl
1417public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); 1662public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1418 1663
1419[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 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]
1420public static extern bool CalculateTransforms2(IntPtr constrain); 1692public static extern bool CalculateTransforms2(IntPtr constrain);
1421 1693
1422[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1694[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1448,6 +1720,9 @@ public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1448public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); 1720public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1449 1721
1450[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1723public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj);
1724
1725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1451public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); 1726public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1452 1727
1453[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1728[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1832,6 +2107,12 @@ public static extern void DumpAllInfo2(IntPtr sim);
1832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 2107[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1833public static extern void DumpPhysicsStatistics2(IntPtr sim); 2108public static extern void DumpPhysicsStatistics2(IntPtr sim);
1834 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
1835} 2116}
1836 2117
1837} 2118}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
index 8ad78ca..7756b10 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
@@ -6,7 +6,7 @@
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
@@ -31,7 +31,7 @@ using System.Security;
31using System.Text; 31using System.Text;
32using OpenMetaverse; 32using OpenMetaverse;
33 33
34namespace OpenSim.Region.Physics.BulletSPlugin { 34namespace OpenSim.Region.PhysicsModule.BulletS {
35 35
36 // Constraint type values as defined by Bullet 36 // Constraint type values as defined by Bullet
37public enum ConstraintType : int 37public enum ConstraintType : int
@@ -43,7 +43,11 @@ public enum ConstraintType : int
43 SLIDER_CONSTRAINT_TYPE, 43 SLIDER_CONSTRAINT_TYPE,
44 CONTACT_CONSTRAINT_TYPE, 44 CONTACT_CONSTRAINT_TYPE,
45 D6_SPRING_CONSTRAINT_TYPE, 45 D6_SPRING_CONSTRAINT_TYPE,
46 MAX_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
47} 51}
48 52
49// =============================================================================== 53// ===============================================================================
@@ -70,6 +74,8 @@ public enum BSPhysicsShapeType
70 SHAPE_COMPOUND = 22, 74 SHAPE_COMPOUND = 22,
71 SHAPE_HEIGHTMAP = 23, 75 SHAPE_HEIGHTMAP = 23,
72 SHAPE_AVATAR = 24, 76 SHAPE_AVATAR = 24,
77 SHAPE_CONVEXHULL= 25,
78 SHAPE_GIMPACT = 26,
73}; 79};
74 80
75// The native shapes have predefined shape hash keys 81// The native shapes have predefined shape hash keys
@@ -87,7 +93,7 @@ public enum FixedShapeKey : ulong
87[StructLayout(LayoutKind.Sequential)] 93[StructLayout(LayoutKind.Sequential)]
88public struct ShapeData 94public struct ShapeData
89{ 95{
90 public uint ID; 96 public UInt32 ID;
91 public BSPhysicsShapeType Type; 97 public BSPhysicsShapeType Type;
92 public Vector3 Position; 98 public Vector3 Position;
93 public Quaternion Rotation; 99 public Quaternion Rotation;
@@ -111,7 +117,7 @@ public struct ShapeData
111[StructLayout(LayoutKind.Sequential)] 117[StructLayout(LayoutKind.Sequential)]
112public struct SweepHit 118public struct SweepHit
113{ 119{
114 public uint ID; 120 public UInt32 ID;
115 public float Fraction; 121 public float Fraction;
116 public Vector3 Normal; 122 public Vector3 Normal;
117 public Vector3 Point; 123 public Vector3 Point;
@@ -119,27 +125,47 @@ public struct SweepHit
119[StructLayout(LayoutKind.Sequential)] 125[StructLayout(LayoutKind.Sequential)]
120public struct RaycastHit 126public struct RaycastHit
121{ 127{
122 public uint ID; 128 public UInt32 ID;
123 public float Fraction; 129 public float Fraction;
124 public Vector3 Normal; 130 public Vector3 Normal;
125} 131}
126[StructLayout(LayoutKind.Sequential)] 132[StructLayout(LayoutKind.Sequential)]
127public struct CollisionDesc 133public struct CollisionDesc
128{ 134{
129 public uint aID; 135 public UInt32 aID;
130 public uint bID; 136 public UInt32 bID;
131 public Vector3 point; 137 public Vector3 point;
132 public Vector3 normal; 138 public Vector3 normal;
139 public float penetration;
133} 140}
134[StructLayout(LayoutKind.Sequential)] 141[StructLayout(LayoutKind.Sequential)]
135public struct EntityProperties 142public struct EntityProperties
136{ 143{
137 public uint ID; 144 public UInt32 ID;
138 public Vector3 Position; 145 public Vector3 Position;
139 public Quaternion Rotation; 146 public Quaternion Rotation;
140 public Vector3 Velocity; 147 public Vector3 Velocity;
141 public Vector3 Acceleration; 148 public Vector3 Acceleration;
142 public Vector3 RotationalVelocity; 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 }
143} 169}
144 170
145// Format of this structure must match the definition in the C++ code 171// Format of this structure must match the definition in the C++ code
@@ -154,32 +180,6 @@ public struct ConfigurationParameters
154 public float collisionMargin; 180 public float collisionMargin;
155 public float gravity; 181 public float gravity;
156 182
157 public float XlinearDamping;
158 public float XangularDamping;
159 public float XdeactivationTime;
160 public float XlinearSleepingThreshold;
161 public float XangularSleepingThreshold;
162 public float XccdMotionThreshold;
163 public float XccdSweptSphereRadius;
164 public float XcontactProcessingThreshold;
165
166 public float XterrainImplementation;
167 public float XterrainFriction;
168 public float XterrainHitFraction;
169 public float XterrainRestitution;
170 public float XterrainCollisionMargin;
171
172 public float XavatarFriction;
173 public float XavatarStandingFriction;
174 public float XavatarDensity;
175 public float XavatarRestitution;
176 public float XavatarCapsuleWidth;
177 public float XavatarCapsuleDepth;
178 public float XavatarCapsuleHeight;
179 public float XavatarContactProcessingThreshold;
180
181 public float XvehicleAngularDamping;
182
183 public float maxPersistantManifoldPoolSize; 183 public float maxPersistantManifoldPoolSize;
184 public float maxCollisionAlgorithmPoolSize; 184 public float maxCollisionAlgorithmPoolSize;
185 public float shouldDisableContactPoolDynamicAllocation; 185 public float shouldDisableContactPoolDynamicAllocation;
@@ -188,22 +188,45 @@ public struct ConfigurationParameters
188 public float shouldSplitSimulationIslands; 188 public float shouldSplitSimulationIslands;
189 public float shouldEnableFrictionCaching; 189 public float shouldEnableFrictionCaching;
190 public float numberOfSolverIterations; 190 public float numberOfSolverIterations;
191 public float useSingleSidedMeshes;
192 public float globalContactBreakingThreshold;
191 193
192 public float XlinksetImplementation; 194 public float physicsLoggingFrames;
193 public float XlinkConstraintUseFrameOffset;
194 public float XlinkConstraintEnableTransMotor;
195 public float XlinkConstraintTransMotorMaxVel;
196 public float XlinkConstraintTransMotorMaxForce;
197 public float XlinkConstraintERP;
198 public float XlinkConstraintCFM;
199 public float XlinkConstraintSolverIterations;
200
201 public float XphysicsLoggingFrames;
202 195
203 public const float numericTrue = 1f; 196 public const float numericTrue = 1f;
204 public const float numericFalse = 0f; 197 public const float numericFalse = 0f;
205} 198}
206 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}
207 230
208// The states a bullet collision object can have 231// The states a bullet collision object can have
209public enum ActivationState : uint 232public enum ActivationState : uint
@@ -238,11 +261,12 @@ public enum CollisionFlags : uint
238 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, 261 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
239 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 262 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
240 // Following used by BulletSim to control collisions and updates 263 // Following used by BulletSim to control collisions and updates
241 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 264 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
242 BS_FLOATS_ON_WATER = 1 << 11, 265 BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
243 BS_VEHICLE_COLLISIONS = 1 << 12, 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
244 BS_NONE = 0, 268 BS_NONE = 0,
245 BS_ALL = 0xFFFFFFFF 269 BS_ALL = 0x7FFF // collision flags are a signed short
246}; 270};
247 271
248// Values f collisions groups and masks 272// Values f collisions groups and masks
@@ -258,14 +282,14 @@ public enum CollisionFilterGroups : uint
258 BDebrisGroup = 1 << 3, // 0008 282 BDebrisGroup = 1 << 3, // 0008
259 BSensorTrigger = 1 << 4, // 0010 283 BSensorTrigger = 1 << 4, // 0010
260 BCharacterGroup = 1 << 5, // 0020 284 BCharacterGroup = 1 << 5, // 0020
261 BAllGroup = 0x000FFFFF, 285 BAllGroup = 0x0007FFF, // collision flags are a signed short
262 // Filter groups defined by BulletSim 286 // Filter groups defined by BulletSim
263 BGroundPlaneGroup = 1 << 10, // 0400 287 BGroundPlaneGroup = 1 << 8, // 0400
264 BTerrainGroup = 1 << 11, // 0800 288 BTerrainGroup = 1 << 9, // 0800
265 BRaycastGroup = 1 << 12, // 1000 289 BRaycastGroup = 1 << 10, // 1000
266 BSolidGroup = 1 << 13, // 2000 290 BSolidGroup = 1 << 11, // 2000
267 // BLinksetGroup = xx // a linkset proper is either static or dynamic 291 // BLinksetGroup = xx // a linkset proper is either static or dynamic
268 BLinksetChildGroup = 1 << 14, // 4000 292 BLinksetChildGroup = 1 << 12, // 4000
269}; 293};
270 294
271// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 295// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@@ -285,7 +309,7 @@ public enum ConstraintParamAxis : int
285 AXIS_ANGULAR_X, 309 AXIS_ANGULAR_X,
286 AXIS_ANGULAR_Y, 310 AXIS_ANGULAR_Y,
287 AXIS_ANGULAR_Z, 311 AXIS_ANGULAR_Z,
288 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls 312 AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls
289 AXIS_ANGULAR_ALL, 313 AXIS_ANGULAR_ALL,
290 AXIS_ALL 314 AXIS_ALL
291}; 315};
@@ -294,7 +318,7 @@ public abstract class BSAPITemplate
294{ 318{
295// Returns the name of the underlying Bullet engine 319// Returns the name of the underlying Bullet engine
296public abstract string BulletEngineName { get; } 320public abstract string BulletEngineName { get; }
297public abstract string BulletEngineVersion { get; protected set;} 321public abstract string BulletEngineVersion { get; protected set;}
298 322
299// Initialization and simulation 323// Initialization and simulation
300public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, 324public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
@@ -305,7 +329,7 @@ public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet
305public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, 329public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
306 out int updatedEntityCount, out int collidersCount); 330 out int updatedEntityCount, out int collidersCount);
307 331
308public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value); 332public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
309 333
310public abstract void Shutdown(BulletWorld sim); 334public abstract void Shutdown(BulletWorld sim);
311 335
@@ -317,10 +341,20 @@ public abstract BulletShape CreateMeshShape(BulletWorld world,
317 int indicesCount, int[] indices, 341 int indicesCount, int[] indices,
318 int verticesCount, float[] vertices ); 342 int verticesCount, float[] vertices );
319 343
344public abstract BulletShape CreateGImpactShape(BulletWorld world,
345 int indicesCount, int[] indices,
346 int verticesCount, float[] vertices );
347
320public abstract BulletShape CreateHullShape(BulletWorld world, 348public abstract BulletShape CreateHullShape(BulletWorld world,
321 int hullCount, float[] hulls); 349 int hullCount, float[] hulls);
322 350
323public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); 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 );
324 358
325public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); 359public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
326 360
@@ -342,26 +376,28 @@ public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape c
342 376
343public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); 377public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
344 378
379public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
380
345public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); 381public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
346 382
347public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id); 383public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
348 384
349public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); 385public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
350 386
351public abstract CollisionObjectTypes GetBodyType(BulletBody obj); 387public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
352 388
353public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); 389public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
354 390
355public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot); 391public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
356 392
357public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); 393public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
358 394
359public abstract void DestroyObject(BulletWorld sim, BulletBody obj); 395public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
360 396
361// ===================================================================================== 397// =====================================================================================
362public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin); 398public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
363 399
364public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 400public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
365 float scaleFactor, float collisionMargin); 401 float scaleFactor, float collisionMargin);
366 402
367// ===================================================================================== 403// =====================================================================================
@@ -375,11 +411,38 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
375 Vector3 joinPoint, 411 Vector3 joinPoint,
376 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 412 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
377 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
378public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 423public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
379 Vector3 pivotinA, Vector3 pivotinB, 424 Vector3 pivotinA, Vector3 pivotinB,
380 Vector3 axisInA, Vector3 axisInB, 425 Vector3 axisInA, Vector3 axisInB,
381 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 426 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
382 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
383public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); 446public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
384 447
385public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); 448public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
@@ -397,6 +460,38 @@ public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float e
397 460
398public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); 461public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
399 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
400public abstract bool CalculateTransforms(BulletConstraint constrain); 495public abstract bool CalculateTransforms(BulletConstraint constrain);
401 496
402public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); 497public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
@@ -420,6 +515,8 @@ public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
420 515
421public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); 516public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
422 517
518public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj);
519
423public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); 520public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
424 521
425public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); 522public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
@@ -607,7 +704,7 @@ public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
607 704
608public abstract int GetNumConstraintRefs(BulletBody obj); 705public abstract int GetNumConstraintRefs(BulletBody obj);
609 706
610public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask); 707public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask);
611 708
612// ===================================================================================== 709// =====================================================================================
613// btCollisionShape entries 710// btCollisionShape entries
@@ -646,17 +743,21 @@ public abstract float GetMargin(BulletShape shape);
646 743
647// ===================================================================================== 744// =====================================================================================
648// Debugging 745// Debugging
649public abstract void DumpRigidBody(BulletWorld sim, BulletBody collisionObject); 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) { }
650 751
651public abstract void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape); 752public virtual void DumpActivationInfo(BulletWorld sim) { }
652 753
653public abstract void DumpConstraint(BulletWorld sim, BulletConstraint constrain); 754public virtual void DumpAllInfo(BulletWorld sim) { }
654 755
655public abstract void DumpActivationInfo(BulletWorld sim); 756public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
656 757
657public abstract void DumpAllInfo(BulletWorld sim); 758public virtual void ResetBroadphasePool(BulletWorld sim) { }
658 759
659public abstract void DumpPhysicsStatistics(BulletWorld sim); 760public virtual void ResetConstraintSolver(BulletWorld sim) { }
660 761
661}; 762};
662} 763}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
index 103d8fc..83fc3a6 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -30,9 +30,9 @@ using System.Reflection;
30using log4net; 30using log4net;
31using OMV = OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.PhysicsModules.SharedBase;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.PhysicsModule.BulletS
36{ 36{
37public sealed class BSCharacter : BSPhysObject 37public sealed class BSCharacter : BSPhysObject
38{ 38{
@@ -43,53 +43,52 @@ public sealed class BSCharacter : BSPhysObject
43 private OMV.Vector3 _size; 43 private OMV.Vector3 _size;
44 private bool _grabbed; 44 private bool _grabbed;
45 private bool _selected; 45 private bool _selected;
46 private OMV.Vector3 _position;
47 private float _mass; 46 private float _mass;
48 private float _avatarDensity;
49 private float _avatarVolume; 47 private float _avatarVolume;
50 private OMV.Vector3 _force;
51 private OMV.Vector3 _velocity;
52 private OMV.Vector3 _torque;
53 private float _collisionScore; 48 private float _collisionScore;
54 private OMV.Vector3 _acceleration; 49 private OMV.Vector3 _acceleration;
55 private OMV.Quaternion _orientation;
56 private int _physicsActorType; 50 private int _physicsActorType;
57 private bool _isPhysical; 51 private bool _isPhysical;
58 private bool _flying; 52 private bool _flying;
59 private bool _setAlwaysRun; 53 private bool _setAlwaysRun;
60 private bool _throttleUpdates; 54 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater; 55 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity; 56 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic; 57 private bool _kinematic;
66 private float _buoyancy; 58 private float _buoyancy;
67 59
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 60 private BSActorAvatarMove m_moveActor;
69 private float _currentFriction; // the friction currently being used (changed by setVelocity). 61 private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
70
71 private BSVMotor _velocityMotor;
72 62
73 private OMV.Vector3 _PIDTarget; 63 private OMV.Vector3 _PIDTarget;
74 private bool _usePID;
75 private float _PIDTau; 64 private float _PIDTau;
76 private bool _useHoverPID;
77 private float _PIDHoverHeight;
78 private PIDHoverType _PIDHoverType;
79 private float _PIDHoverTao;
80 65
81 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) 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
82 : base(parent_scene, localID, avName, "BSCharacter") 81 : base(parent_scene, localID, avName, "BSCharacter")
83 { 82 {
84 _physicsActorType = (int)ActorTypes.Agent; 83 _physicsActorType = (int)ActorTypes.Agent;
85 _position = pos; 84 RawPosition = pos;
86 85
87 _flying = isFlying; 86 _flying = isFlying;
88 _orientation = OMV.Quaternion.Identity; 87 RawOrientation = OMV.Quaternion.Identity;
89 _velocity = OMV.Vector3.Zero; 88 RawVelocity = vel;
90 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 89 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
91 _currentFriction = BSParam.AvatarStandingFriction; 90 Friction = BSParam.AvatarStandingFriction;
92 _avatarDensity = BSParam.AvatarDensity; 91 Density = BSParam.AvatarDensity;
93 92
94 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 93 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
95 // replace with the default values. 94 // replace with the default values.
@@ -103,19 +102,28 @@ public sealed class BSCharacter : BSPhysObject
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 102 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 103 ComputeAvatarVolumeAndMass();
105 104
106 SetupMovementMotor(); 105 DetailLog(
107 106 "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}",
108 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 107 LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel);
109 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
110 108
111 // do actual creation in taint time 109 // do actual creation in taint time
112 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 110 PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
113 { 111 {
114 DetailLog("{0},BSCharacter.create,taint", LocalID); 112 DetailLog("{0},BSCharacter.create,taint", LocalID);
113
115 // New body and shape into PhysBody and PhysShape 114 // New body and shape into PhysBody and PhysShape
116 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); 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);
117 123
118 SetPhysicalProperties(); 124 SetPhysicalProperties();
125
126 IsInitialized = true;
119 }); 127 });
120 return; 128 return;
121 } 129 }
@@ -123,122 +131,77 @@ public sealed class BSCharacter : BSPhysObject
123 // called when this character is being destroyed and the resources should be released 131 // called when this character is being destroyed and the resources should be released
124 public override void Destroy() 132 public override void Destroy()
125 { 133 {
134 IsInitialized = false;
135
126 base.Destroy(); 136 base.Destroy();
127 137
128 DetailLog("{0},BSCharacter.Destroy", LocalID); 138 DetailLog("{0},BSCharacter.Destroy", LocalID);
129 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 139 PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
130 { 140 {
131 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 141 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
132 PhysBody.Clear(); 142 PhysBody.Clear();
133 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 143 PhysShape.Dereference(PhysScene);
134 PhysShape.Clear(); 144 PhysShape = new BSShapeNull();
135 }); 145 });
136 } 146 }
137 147
138 private void SetPhysicalProperties() 148 private void SetPhysicalProperties()
139 { 149 {
140 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 150 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
151
152 ForcePosition = RawPosition;
141 153
142 ZeroMotion(true); 154 // Set the velocity
143 ForcePosition = _position; 155 if (m_moveActor != null)
156 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
144 157
145 // Set the velocity and compute the proper friction 158 ForceVelocity = RawVelocity;
146 _velocityMotor.Reset(); 159 TargetVelocity = RawVelocity;
147 _velocityMotor.SetTarget(_velocity);
148 _velocityMotor.SetCurrent(_velocity);
149 ForceVelocity = _velocity;
150 160
151 // This will enable or disable the flying buoyancy of the avatar. 161 // This will enable or disable the flying buoyancy of the avatar.
152 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 162 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
153 Flying = _flying; 163 Flying = _flying;
154 164
155 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); 165 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
156 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); 166 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
157 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 167 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
158 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 168 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
159 if (BSParam.CcdMotionThreshold > 0f) 169 if (BSParam.CcdMotionThreshold > 0f)
160 { 170 {
161 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 171 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
162 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 172 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
163 } 173 }
164 174
165 UpdatePhysicalMassProperties(RawMass, false); 175 UpdatePhysicalMassProperties(RawMass, false);
166 176
167 // Make so capsule does not fall over 177 // Make so capsule does not fall over
168 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); 178 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
169 179
170 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); 180 // The avatar mover sets some parameters.
181 PhysicalActors.Refresh();
171 182
172 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 183 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
184
185 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
173 186
174 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 187 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
175 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); 188 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
176 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 189 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
177 190
178 // Do this after the object has been added to the world 191 // Do this after the object has been added to the world
179 PhysBody.collisionType = CollisionType.Avatar; 192 if (BSParam.AvatarToAvatarCollisionsByDefault)
180 PhysBody.ApplyCollisionMask(PhysicsScene); 193 PhysBody.collisionType = CollisionType.Avatar;
181 } 194 else
182 195 PhysBody.collisionType = CollisionType.PhantomToOthersAvatar;
183 // The avatar's movement is controlled by this motor that speeds up and slows down
184 // the avatar seeking to reach the motor's target speed.
185 // This motor runs as a prestep action for the avatar so it will keep the avatar
186 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
187 private void SetupMovementMotor()
188 {
189
190 // Someday, use a PID motor for asymmetric speed up and slow down
191 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
192
193 // Infinite decay and timescale values so motor only changes current to target values.
194 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
195 0.2f, // time scale
196 BSMotor.Infinite, // decay time scale
197 BSMotor.InfiniteVector, // friction timescale
198 1f // efficiency
199 );
200 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
201
202 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
203 {
204 // TODO: Decide if the step parameters should be changed depending on the avatar's
205 // state (flying, colliding, ...). There is code in ODE to do this.
206
207 OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
208
209 // If falling, we keep the world's downward vector no matter what the other axis specify.
210 if (!Flying && !IsColliding)
211 {
212 stepVelocity.Z = _velocity.Z;
213 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
214 }
215
216 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
217 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep;
218 196
219 /* 197 PhysBody.ApplyCollisionMask(PhysScene);
220 // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user
221 float moveForceMagnitudeSquared = moveForce.LengthSquared();
222 if (moveForceMagnitudeSquared < 0.0001)
223 {
224 DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}",
225 LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce);
226 ForceVelocity = OMV.Vector3.Zero;
227 }
228 else
229 {
230 AddForce(moveForce, false, true);
231 }
232 */
233 // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
234 AddForce(moveForce, false, true);
235 });
236 } 198 }
237 199
238 public override void RequestPhysicsterseUpdate() 200 public override void RequestPhysicsterseUpdate()
239 { 201 {
240 base.RequestPhysicsterseUpdate(); 202 base.RequestPhysicsterseUpdate();
241 } 203 }
204
242 // No one calls this method so I don't know what it could possibly mean 205 // No one calls this method so I don't know what it could possibly mean
243 public override bool Stopped { get { return false; } } 206 public override bool Stopped { get { return false; } }
244 207
@@ -250,6 +213,10 @@ public sealed class BSCharacter : BSPhysObject
250 } 213 }
251 214
252 set { 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
253 _size = value; 220 _size = value;
254 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 221 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
255 // replace with the default values. 222 // replace with the default values.
@@ -259,16 +226,20 @@ public sealed class BSCharacter : BSPhysObject
259 Scale = ComputeAvatarScale(_size); 226 Scale = ComputeAvatarScale(_size);
260 ComputeAvatarVolumeAndMass(); 227 ComputeAvatarVolumeAndMass();
261 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 228 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
262 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 229 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
263 230
264 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 231 PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
265 { 232 {
266 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) 233 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
267 { 234 {
268 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 235 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
269 UpdatePhysicalMassProperties(RawMass, true); 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
270 // Make sure this change appears as a property update event 241 // Make sure this change appears as a property update event
271 PhysicsScene.PE.PushUpdate(PhysBody); 242 PhysScene.PE.PushUpdate(PhysBody);
272 } 243 }
273 }); 244 });
274 245
@@ -279,11 +250,6 @@ public sealed class BSCharacter : BSPhysObject
279 { 250 {
280 set { BaseShape = value; } 251 set { BaseShape = value; }
281 } 252 }
282 // I want the physics engine to make an avatar capsule
283 public override BSPhysicsShapeType PreferredPhysicalShape
284 {
285 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
286 }
287 253
288 public override bool Grabbed { 254 public override bool Grabbed {
289 set { _grabbed = value; } 255 set { _grabbed = value; }
@@ -291,6 +257,10 @@ public sealed class BSCharacter : BSPhysObject
291 public override bool Selected { 257 public override bool Selected {
292 set { _selected = value; } 258 set { _selected = value; }
293 } 259 }
260 public override bool IsSelected
261 {
262 get { return _selected; }
263 }
294 public override void CrossingFailure() { return; } 264 public override void CrossingFailure() { return; }
295 public override void link(PhysicsActor obj) { return; } 265 public override void link(PhysicsActor obj) { return; }
296 public override void delink() { return; } 266 public override void delink() { return; }
@@ -301,29 +271,30 @@ public sealed class BSCharacter : BSPhysObject
301 // Called at taint time! 271 // Called at taint time!
302 public override void ZeroMotion(bool inTaintTime) 272 public override void ZeroMotion(bool inTaintTime)
303 { 273 {
304 _velocity = OMV.Vector3.Zero; 274 RawVelocity = OMV.Vector3.Zero;
305 _acceleration = OMV.Vector3.Zero; 275 _acceleration = OMV.Vector3.Zero;
306 _rotationalVelocity = OMV.Vector3.Zero; 276 _rotationalVelocity = OMV.Vector3.Zero;
307 277
308 // Zero some other properties directly into the physics engine 278 // Zero some other properties directly into the physics engine
309 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 279 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
310 { 280 {
311 if (PhysBody.HasPhysicalBody) 281 if (PhysBody.HasPhysicalBody)
312 PhysicsScene.PE.ClearAllForces(PhysBody); 282 PhysScene.PE.ClearAllForces(PhysBody);
313 }); 283 });
314 } 284 }
285
315 public override void ZeroAngularMotion(bool inTaintTime) 286 public override void ZeroAngularMotion(bool inTaintTime)
316 { 287 {
317 _rotationalVelocity = OMV.Vector3.Zero; 288 _rotationalVelocity = OMV.Vector3.Zero;
318 289
319 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 290 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
320 { 291 {
321 if (PhysBody.HasPhysicalBody) 292 if (PhysBody.HasPhysicalBody)
322 { 293 {
323 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); 294 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
324 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); 295 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
325 // The next also get rid of applied linear force but the linear velocity is untouched. 296 // The next also get rid of applied linear force but the linear velocity is untouched.
326 PhysicsScene.PE.ClearForces(PhysBody); 297 PhysScene.PE.ClearForces(PhysBody);
327 } 298 }
328 }); 299 });
329 } 300 }
@@ -331,38 +302,34 @@ public sealed class BSCharacter : BSPhysObject
331 302
332 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 303 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
333 304
334 public override OMV.Vector3 RawPosition
335 {
336 get { return _position; }
337 set { _position = value; }
338 }
339 public override OMV.Vector3 Position { 305 public override OMV.Vector3 Position {
340 get { 306 get {
341 // Don't refetch the position because this function is called a zillion times 307 // Don't refetch the position because this function is called a zillion times
342 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); 308 // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
343 return _position; 309 return RawPosition;
344 } 310 }
345 set { 311 set {
346 _position = value; 312 RawPosition = value;
347 PositionSanityCheck();
348 313
349 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 314 PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
350 { 315 {
351 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 316 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
352 if (PhysBody.HasPhysicalBody) 317 PositionSanityCheck();
353 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 318 ForcePosition = RawPosition;
354 }); 319 });
355 } 320 }
356 } 321 }
357 public override OMV.Vector3 ForcePosition { 322 public override OMV.Vector3 ForcePosition {
358 get { 323 get {
359 _position = PhysicsScene.PE.GetPosition(PhysBody); 324 RawPosition = PhysScene.PE.GetPosition(PhysBody);
360 return _position; 325 return RawPosition;
361 } 326 }
362 set { 327 set {
363 _position = value; 328 RawPosition = value;
364 PositionSanityCheck(); 329 if (PhysBody.HasPhysicalBody)
365 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 330 {
331 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
332 }
366 } 333 }
367 } 334 }
368 335
@@ -375,28 +342,30 @@ public sealed class BSCharacter : BSPhysObject
375 bool ret = false; 342 bool ret = false;
376 343
377 // TODO: check for out of bounds 344 // TODO: check for out of bounds
378 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) 345 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
379 { 346 {
380 // The character is out of the known/simulated area. 347 // The character is out of the known/simulated area.
381 // Upper levels of code will handle the transition to other areas so, for 348 // Force the avatar position to be within known. ScenePresence will use the position
382 // the time, we just ignore the position. 349 // plus the velocity to decide if the avatar is moving out of the region.
383 return ret; 350 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
351 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
352 return true;
384 } 353 }
385 354
386 // If below the ground, move the avatar up 355 // If below the ground, move the avatar up
387 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 356 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
388 if (Position.Z < terrainHeight) 357 if (Position.Z < terrainHeight)
389 { 358 {
390 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 359 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
391 _position.Z = terrainHeight + 2.0f; 360 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
392 ret = true; 361 ret = true;
393 } 362 }
394 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 363 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
395 { 364 {
396 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 365 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
397 if (Position.Z < waterHeight) 366 if (Position.Z < waterHeight)
398 { 367 {
399 _position.Z = waterHeight; 368 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
400 ret = true; 369 ret = true;
401 } 370 }
402 } 371 }
@@ -414,11 +383,10 @@ public sealed class BSCharacter : BSPhysObject
414 { 383 {
415 // The new position value must be pushed into the physics engine but we can't 384 // The new position value must be pushed into the physics engine but we can't
416 // just assign to "Position" because of potential call loops. 385 // just assign to "Position" because of potential call loops.
417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 386 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
418 { 387 {
419 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 388 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
420 if (PhysBody.HasPhysicalBody) 389 ForcePosition = RawPosition;
421 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
422 }); 390 });
423 ret = true; 391 ret = true;
424 } 392 }
@@ -428,25 +396,25 @@ public sealed class BSCharacter : BSPhysObject
428 public override float Mass { get { return _mass; } } 396 public override float Mass { get { return _mass; } }
429 397
430 // used when we only want this prim's mass and not the linkset thing 398 // used when we only want this prim's mass and not the linkset thing
431 public override float RawMass { 399 public override float RawMass {
432 get {return _mass; } 400 get {return _mass; }
433 } 401 }
434 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 402 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
435 { 403 {
436 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 404 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
437 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); 405 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
438 } 406 }
439 407
440 public override OMV.Vector3 Force { 408 public override OMV.Vector3 Force {
441 get { return _force; } 409 get { return RawForce; }
442 set { 410 set {
443 _force = value; 411 RawForce = value;
444 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 412 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
445 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 413 PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
446 { 414 {
447 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 415 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
448 if (PhysBody.HasPhysicalBody) 416 if (PhysBody.HasPhysicalBody)
449 PhysicsScene.PE.SetObjectForce(PhysBody, _force); 417 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
450 }); 418 });
451 } 419 }
452 } 420 }
@@ -460,6 +428,7 @@ public sealed class BSCharacter : BSPhysObject
460 428
461 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 429 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
462 public override void SetVolumeDetect(int param) { return; } 430 public override void SetVolumeDetect(int param) { return; }
431 public override bool IsVolumeDetect { get { return false; } }
463 432
464 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 433 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
465 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 434 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
@@ -469,79 +438,59 @@ public sealed class BSCharacter : BSPhysObject
469 { 438 {
470 get 439 get
471 { 440 {
472 return _velocityMotor.TargetValue; 441 return base.m_targetVelocity;
473 } 442 }
474 set 443 set
475 { 444 {
476 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); 445 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
446 m_targetVelocity = value;
477 OMV.Vector3 targetVel = value; 447 OMV.Vector3 targetVel = value;
478 if (_setAlwaysRun) 448 if (_setAlwaysRun && !_flying)
479 targetVel *= BSParam.AvatarAlwaysRunFactor; 449 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f);
480 450
481 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() 451 if (m_moveActor != null)
482 { 452 m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
483 _velocityMotor.Reset();
484 _velocityMotor.SetTarget(targetVel);
485 _velocityMotor.SetCurrent(_velocity);
486 _velocityMotor.Enabled = true;
487 });
488 } 453 }
489 } 454 }
490 // Directly setting velocity means this is what the user really wants now. 455 // Directly setting velocity means this is what the user really wants now.
491 public override OMV.Vector3 Velocity { 456 public override OMV.Vector3 Velocity {
492 get { return _velocity; } 457 get { return RawVelocity; }
493 set { 458 set {
494 _velocity = value; 459 RawVelocity = value;
495 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 460 OMV.Vector3 vel = RawVelocity;
496 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 461
462 DetailLog("{0}: set Velocity = {1}", LocalID, value);
463
464 PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
497 { 465 {
498 _velocityMotor.Reset(); 466 if (m_moveActor != null)
499 _velocityMotor.SetCurrent(_velocity); 467 m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */);
500 _velocityMotor.SetTarget(_velocity); 468
501 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. 469 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel);
502 _velocityMotor.Enabled = false; 470 ForceVelocity = vel;
503
504 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
505 ForceVelocity = _velocity;
506 }); 471 });
507 } 472 }
508 } 473 }
474
509 public override OMV.Vector3 ForceVelocity { 475 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 476 get { return RawVelocity; }
511 set { 477 set {
512 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 478 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
479// Util.PrintCallStack();
480 DetailLog("{0}: set ForceVelocity = {1}", LocalID, value);
513 481
514 _velocity = value; 482 RawVelocity = value;
515 // Depending on whether the avatar is moving or not, change the friction 483 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
516 // to keep the avatar from slipping around 484 PhysScene.PE.Activate(PhysBody, true);
517 if (_velocity.Length() == 0)
518 {
519 if (_currentFriction != BSParam.AvatarStandingFriction)
520 {
521 _currentFriction = BSParam.AvatarStandingFriction;
522 if (PhysBody.HasPhysicalBody)
523 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
524 }
525 }
526 else
527 {
528 if (_currentFriction != BSParam.AvatarFriction)
529 {
530 _currentFriction = BSParam.AvatarFriction;
531 if (PhysBody.HasPhysicalBody)
532 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
533 }
534 }
535
536 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
537 PhysicsScene.PE.Activate(PhysBody, true);
538 } 485 }
539 } 486 }
487
540 public override OMV.Vector3 Torque { 488 public override OMV.Vector3 Torque {
541 get { return _torque; } 489 get { return RawTorque; }
542 set { _torque = value; 490 set { RawTorque = value;
543 } 491 }
544 } 492 }
493
545 public override float CollisionScore { 494 public override float CollisionScore {
546 get { return _collisionScore; } 495 get { return _collisionScore; }
547 set { _collisionScore = value; 496 set { _collisionScore = value;
@@ -551,22 +500,27 @@ public sealed class BSCharacter : BSPhysObject
551 get { return _acceleration; } 500 get { return _acceleration; }
552 set { _acceleration = value; } 501 set { _acceleration = value; }
553 } 502 }
554 public override OMV.Quaternion RawOrientation
555 {
556 get { return _orientation; }
557 set { _orientation = value; }
558 }
559 public override OMV.Quaternion Orientation { 503 public override OMV.Quaternion Orientation {
560 get { return _orientation; } 504 get { return RawOrientation; }
561 set { 505 set {
562 // Orientation is set zillions of times when an avatar is walking. It's like 506 // Orientation is set zillions of times when an avatar is walking. It's like
563 // the viewer doesn't trust us. 507 // the viewer doesn't trust us.
564 if (_orientation != value) 508 if (RawOrientation != value)
565 { 509 {
566 _orientation = value; 510 RawOrientation = value;
567 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 511 PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
568 { 512 {
569 ForceOrientation = _orientation; 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;
570 }); 524 });
571 } 525 }
572 } 526 }
@@ -576,16 +530,16 @@ public sealed class BSCharacter : BSPhysObject
576 { 530 {
577 get 531 get
578 { 532 {
579 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 533 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
580 return _orientation; 534 return RawOrientation;
581 } 535 }
582 set 536 set
583 { 537 {
584 _orientation = value; 538 RawOrientation = value;
585 if (PhysBody.HasPhysicalBody) 539 if (PhysBody.HasPhysicalBody)
586 { 540 {
587 // _position = PhysicsScene.PE.GetPosition(BSBody); 541 // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
588 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 542 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
589 } 543 }
590 } 544 }
591 } 545 }
@@ -605,6 +559,9 @@ public sealed class BSCharacter : BSPhysObject
605 public override bool IsStatic { 559 public override bool IsStatic {
606 get { return false; } 560 get { return false; }
607 } 561 }
562 public override bool IsPhysicallyActive {
563 get { return true; }
564 }
608 public override bool Flying { 565 public override bool Flying {
609 get { return _flying; } 566 get { return _flying; }
610 set { 567 set {
@@ -631,14 +588,14 @@ public sealed class BSCharacter : BSPhysObject
631 public override bool FloatOnWater { 588 public override bool FloatOnWater {
632 set { 589 set {
633 _floatOnWater = value; 590 _floatOnWater = value;
634 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 591 PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
635 { 592 {
636 if (PhysBody.HasPhysicalBody) 593 if (PhysBody.HasPhysicalBody)
637 { 594 {
638 if (_floatOnWater) 595 if (_floatOnWater)
639 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 596 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
640 else 597 else
641 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 598 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
642 } 599 }
643 }); 600 });
644 } 601 }
@@ -659,7 +616,7 @@ public sealed class BSCharacter : BSPhysObject
659 public override float Buoyancy { 616 public override float Buoyancy {
660 get { return _buoyancy; } 617 get { return _buoyancy; }
661 set { _buoyancy = value; 618 set { _buoyancy = value;
662 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 619 PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
663 { 620 {
664 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 621 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
665 ForceBuoyancy = _buoyancy; 622 ForceBuoyancy = _buoyancy;
@@ -668,15 +625,16 @@ public sealed class BSCharacter : BSPhysObject
668 } 625 }
669 public override float ForceBuoyancy { 626 public override float ForceBuoyancy {
670 get { return _buoyancy; } 627 get { return _buoyancy; }
671 set { 628 set {
672 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); 629 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
673 630
674 _buoyancy = value; 631 _buoyancy = value;
675 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 632 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
676 // Buoyancy is faked by changing the gravity applied to the object 633 // Buoyancy is faked by changing the gravity applied to the object
677 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 634 float grav = BSParam.Gravity * (1f - _buoyancy);
635 Gravity = new OMV.Vector3(0f, 0f, grav);
678 if (PhysBody.HasPhysicalBody) 636 if (PhysBody.HasPhysicalBody)
679 PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); 637 PhysScene.PE.SetGravity(PhysBody, Gravity);
680 } 638 }
681 } 639 }
682 640
@@ -684,60 +642,32 @@ public sealed class BSCharacter : BSPhysObject
684 public override OMV.Vector3 PIDTarget { 642 public override OMV.Vector3 PIDTarget {
685 set { _PIDTarget = value; } 643 set { _PIDTarget = value; }
686 } 644 }
687 public override bool PIDActive { 645
688 set { _usePID = value; } 646 public override bool PIDActive { get; set; }
689 } 647
690 public override float PIDTau { 648 public override float PIDTau {
691 set { _PIDTau = value; } 649 set { _PIDTau = value; }
692 } 650 }
693 651
694 // Used for llSetHoverHeight and maybe vehicle height
695 // Hover Height will override MoveTo target's Z
696 public override bool PIDHoverActive {
697 set { _useHoverPID = value; }
698 }
699 public override float PIDHoverHeight {
700 set { _PIDHoverHeight = value; }
701 }
702 public override PIDHoverType PIDHoverType {
703 set { _PIDHoverType = value; }
704 }
705 public override float PIDHoverTau {
706 set { _PIDHoverTao = value; }
707 }
708
709 // For RotLookAt
710 public override OMV.Quaternion APIDTarget { set { return; } }
711 public override bool APIDActive { set { return; } }
712 public override float APIDStrength { set { return; } }
713 public override float APIDDamping { set { return; } }
714
715 public override void AddForce(OMV.Vector3 force, bool pushforce) 652 public override void AddForce(OMV.Vector3 force, bool pushforce)
716 { 653 {
717 // Since this force is being applied in only one step, make this a force per second. 654 // Since this force is being applied in only one step, make this a force per second.
718 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 655 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
719 AddForce(addForce, pushforce, false); 656 AddForce(addForce, pushforce, false);
720 } 657 }
721 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 658 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
722 if (force.IsFinite()) 659 if (force.IsFinite())
723 { 660 {
724 float magnitude = force.Length(); 661 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
725 if (magnitude > BSParam.MaxAddForceMagnitude)
726 {
727 // Force has a limit
728 force = force / magnitude * BSParam.MaxAddForceMagnitude;
729 }
730
731 OMV.Vector3 addForce = force;
732 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); 662 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
733 663
734 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() 664 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
735 { 665 {
736 // Bullet adds this central force to the total force for this tick 666 // Bullet adds this central force to the total force for this tick
737 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); 667 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
738 if (PhysBody.HasPhysicalBody) 668 if (PhysBody.HasPhysicalBody)
739 { 669 {
740 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 670 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
741 } 671 }
742 }); 672 });
743 } 673 }
@@ -748,35 +678,66 @@ public sealed class BSCharacter : BSPhysObject
748 } 678 }
749 } 679 }
750 680
751 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 681 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
752 } 682 }
753 public override void SetMomentum(OMV.Vector3 momentum) { 683 public override void SetMomentum(OMV.Vector3 momentum) {
754 } 684 }
755 685
756 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) 686 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
757 { 687 {
758 OMV.Vector3 newScale; 688 OMV.Vector3 newScale = size;
759 689
760 // Bullet's capsule total height is the "passed height + radius * 2"; 690 // Bullet's capsule total height is the "passed height + radius * 2";
761 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) 691 // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
762 // The number we pass in for 'scaling' is the multiplier to get that base 692 // The number we pass in for 'scaling' is the multiplier to get that base
763 // shape to be the size desired. 693 // shape to be the size desired.
764 // So, when creating the scale for the avatar height, we take the passed height 694 // So, when creating the scale for the avatar height, we take the passed height
765 // (size.Z) and remove the caps. 695 // (size.Z) and remove the caps.
766 // Another oddity of the Bullet capsule implementation is that it presumes the Y 696 // An oddity of the Bullet capsule implementation is that it presumes the Y
767 // dimension is the radius of the capsule. Even though some of the code allows 697 // dimension is the radius of the capsule. Even though some of the code allows
768 // for a asymmetrical capsule, other parts of the code presume it is cylindrical. 698 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
769 699
770 // Scale is multiplier of radius with one of "0.5" 700 // Scale is multiplier of radius with one of "0.5"
771 newScale.X = size.X / 2f;
772 newScale.Y = size.Y / 2f;
773 701
774 // The total scale height is the central cylindar plus the caps on the two ends. 702 float heightAdjust = BSParam.AvatarHeightMidFudge;
775 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; 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
776 // If smaller than the endcaps, just fake like we're almost that small 734 // If smaller than the endcaps, just fake like we're almost that small
777 if (newScale.Z < 0) 735 if (newScale.Z < 0)
778 newScale.Z = 0.1f; 736 newScale.Z = 0.1f;
779 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
780 return newScale; 741 return newScale;
781 } 742 }
782 743
@@ -794,34 +755,59 @@ public sealed class BSCharacter : BSPhysObject
794 * Math.Min(Size.X, Size.Y) / 2 755 * Math.Min(Size.X, Size.Y) / 2
795 * Size.Y / 2f // plus the volume of the capsule end caps 756 * Size.Y / 2f // plus the volume of the capsule end caps
796 ); 757 );
797 _mass = _avatarDensity * _avatarVolume; 758 _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
798 } 759 }
799 760
800 // The physics engine says that properties have updated. Update same and inform 761 // The physics engine says that properties have updated. Update same and inform
801 // the world that things have changed. 762 // the world that things have changed.
802 public override void UpdateProperties(EntityProperties entprop) 763 public override void UpdateProperties(EntityProperties entprop)
803 { 764 {
804 _position = entprop.Position; 765 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
805 _orientation = entprop.Rotation; 766 TriggerPreUpdatePropertyAction(ref entprop);
806 _velocity = entprop.Velocity; 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
807 _acceleration = entprop.Acceleration; 789 _acceleration = entprop.Acceleration;
808 _rotationalVelocity = entprop.RotationalVelocity; 790 _rotationalVelocity = entprop.RotationalVelocity;
809 791
810 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 792 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
811 PositionSanityCheck(true); 793 if (PositionSanityCheck(true))
794 {
795 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
796 entprop.Position = RawPosition;
797 }
812 798
813 // remember the current and last set values 799 // remember the current and last set values
814 LastEntityProperties = CurrentEntityProperties; 800 LastEntityProperties = CurrentEntityProperties;
815 CurrentEntityProperties = entprop; 801 CurrentEntityProperties = entprop;
816 802
817 // Tell the linkset about value changes 803 // Tell the linkset about value changes
818 Linkset.UpdateProperties(this, true); 804 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
819 805
820 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 806 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
821 // base.RequestPhysicsterseUpdate(); 807 // PhysScene.PostUpdate(this);
822 808
823 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 809 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
824 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 810 LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
825 } 811 }
826} 812}
827} 813}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
index b813974..e42e868 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
@@ -29,7 +29,7 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34 34
35public abstract class BSConstraint : IDisposable 35public abstract class BSConstraint : IDisposable
@@ -64,7 +64,7 @@ public abstract class BSConstraint : IDisposable
64 { 64 {
65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); 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}", 66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
67 BSScene.DetailLogZero, 67 m_body1.ID,
68 m_body1.ID, m_body1.AddrString, 68 m_body1.ID, m_body1.AddrString,
69 m_body2.ID, m_body2.AddrString, 69 m_body2.ID, m_body2.AddrString,
70 success); 70 success);
@@ -77,7 +77,10 @@ public abstract class BSConstraint : IDisposable
77 { 77 {
78 bool ret = false; 78 bool ret = false;
79 if (m_enabled) 79 if (m_enabled)
80 {
81 m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high);
80 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); 82 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
83 }
81 return ret; 84 return ret;
82 } 85 }
83 86
@@ -85,7 +88,10 @@ public abstract class BSConstraint : IDisposable
85 { 88 {
86 bool ret = false; 89 bool ret = false;
87 if (m_enabled) 90 if (m_enabled)
91 {
92 m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high);
88 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); 93 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
94 }
89 return ret; 95 return ret;
90 } 96 }
91 97
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
index ecb1b32..4bcde2b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
@@ -29,15 +29,22 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34 34
35public sealed class BSConstraint6Dof : BSConstraint 35public class BSConstraint6Dof : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; 37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38 38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40 40
41 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
41 // Create a btGeneric6DofConstraint 48 // Create a btGeneric6DofConstraint
42 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, 49 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot, 50 Vector3 frame1, Quaternion frame1rot,
@@ -52,11 +59,14 @@ public sealed class BSConstraint6Dof : BSConstraint
52 frame2, frame2rot, 59 frame2, frame2rot,
53 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 60 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
54 m_enabled = true; 61 m_enabled = true;
55 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 62 PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
56 BSScene.DetailLogZero, world.worldID, 63 m_body1.ID, world.worldID,
57 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); 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);
58 } 67 }
59 68
69 // 6 Dof constraint based on a midpoint between the two constrained bodies
60 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, 70 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
61 Vector3 joinPoint, 71 Vector3 joinPoint,
62 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 72 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
@@ -78,9 +88,11 @@ public sealed class BSConstraint6Dof : BSConstraint
78 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, 88 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
79 joinPoint, 89 joinPoint,
80 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 90 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
91
81 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 92 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
82 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString, 93 m_body1.ID, world.worldID, m_constraint.AddrString,
83 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); 94 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
95
84 if (!m_constraint.HasPhysicalConstraint) 96 if (!m_constraint.HasPhysicalConstraint)
85 { 97 {
86 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 98 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
@@ -94,6 +106,23 @@ public sealed class BSConstraint6Dof : BSConstraint
94 } 106 }
95 } 107 }
96 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
97 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 126 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
98 { 127 {
99 bool ret = false; 128 bool ret = false;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
index 7714a03..d20538d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
@@ -29,7 +29,7 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34 34
35public sealed class BSConstraintHinge : BSConstraint 35public sealed class BSConstraintHinge : BSConstraint
@@ -45,7 +45,7 @@ public sealed class BSConstraintHinge : BSConstraint
45 m_body1 = obj1; 45 m_body1 = obj1;
46 m_body2 = obj2; 46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, 47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 pivotInA, pivotInB, axisInA, axisInB, 48 pivotInA, pivotInB, axisInA, axisInB,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true; 50 m_enabled = true;
51 } 51 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
index 92d62ff..0e44d03 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
@@ -30,7 +30,7 @@ using System.Text;
30using System.Reflection; 30using System.Reflection;
31using Nini.Config; 31using Nini.Config;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.PhysicsModule.BulletS
34{ 34{
35 35
36public struct MaterialAttributes 36public struct MaterialAttributes
@@ -180,11 +180,14 @@ public static class BSMaterials
180 // Use reflection to set the value in the attribute structure. 180 // Use reflection to set the value in the attribute structure.
181 private static void SetAttributeValue(int matType, string attribName, float val) 181 private static void SetAttributeValue(int matType, string attribName, float val)
182 { 182 {
183 // Get the current attribute values for this material
183 MaterialAttributes thisAttrib = Attributes[matType]; 184 MaterialAttributes thisAttrib = Attributes[matType];
185 // Find the field for the passed attribute name (eg, find field named 'friction')
184 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); 186 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
185 if (fieldInfo != null) 187 if (fieldInfo != null)
186 { 188 {
187 fieldInfo.SetValue(thisAttrib, val); 189 fieldInfo.SetValue(thisAttrib, val);
190 // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
188 Attributes[matType] = thisAttrib; 191 Attributes[matType] = thisAttrib;
189 } 192 }
190 } 193 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
index 817a5f7..2faf2d4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
@@ -31,7 +31,7 @@ using System.Text;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33 33
34namespace OpenSim.Region.Physics.BulletSPlugin 34namespace OpenSim.Region.PhysicsModule.BulletS
35{ 35{
36public abstract class BSMotor 36public abstract class BSMotor
37{ 37{
@@ -59,22 +59,17 @@ public abstract class BSMotor
59 { 59 {
60 if (PhysicsScene != null) 60 if (PhysicsScene != null)
61 { 61 {
62 if (PhysicsScene.VehicleLoggingEnabled) 62 PhysicsScene.DetailLog(msg, parms);
63 {
64 PhysicsScene.DetailLog(msg, parms);
65 }
66 } 63 }
67 } 64 }
68} 65}
69 66
70// Motor which moves CurrentValue to TargetValue over TimeScale seconds. 67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
71// The TargetValue decays in TargetValueDecayTimeScale and 68// The TargetValue decays in TargetValueDecayTimeScale.
72// the CurrentValue will be held back by FrictionTimeScale.
73// This motor will "zero itself" over time in that the targetValue will 69// This motor will "zero itself" over time in that the targetValue will
74// decay to zero and the currentValue will follow it to that zero. 70// decay to zero and the currentValue will follow it to that zero.
75// The overall effect is for the returned correction value to go from large 71// The overall effect is for the returned correction value to go from large
76// values (the total difference between current and target minus friction) 72// values to small and eventually zero values.
77// to small and eventually zero values.
78// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. 73// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
79 74
80// For instance, if something is moving at speed X and the desired speed is Y, 75// For instance, if something is moving at speed X and the desired speed is Y,
@@ -91,7 +86,6 @@ public class BSVMotor : BSMotor
91 86
92 public virtual float TimeScale { get; set; } 87 public virtual float TimeScale { get; set; }
93 public virtual float TargetValueDecayTimeScale { get; set; } 88 public virtual float TargetValueDecayTimeScale { get; set; }
94 public virtual Vector3 FrictionTimescale { get; set; }
95 public virtual float Efficiency { get; set; } 89 public virtual float Efficiency { get; set; }
96 90
97 public virtual float ErrorZeroThreshold { get; set; } 91 public virtual float ErrorZeroThreshold { get; set; }
@@ -100,10 +94,13 @@ public class BSVMotor : BSMotor
100 public virtual Vector3 CurrentValue { get; protected set; } 94 public virtual Vector3 CurrentValue { get; protected set; }
101 public virtual Vector3 LastError { get; protected set; } 95 public virtual Vector3 LastError { get; protected set; }
102 96
103 public virtual bool ErrorIsZero 97 public virtual bool ErrorIsZero()
104 { get { 98 {
105 return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold); 99 return ErrorIsZero(LastError);
106 } 100 }
101 public virtual bool ErrorIsZero(Vector3 err)
102 {
103 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
107 } 104 }
108 105
109 public BSVMotor(string useName) 106 public BSVMotor(string useName)
@@ -111,16 +108,14 @@ public class BSVMotor : BSMotor
111 { 108 {
112 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; 109 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
113 Efficiency = 1f; 110 Efficiency = 1f;
114 FrictionTimescale = BSMotor.InfiniteVector;
115 CurrentValue = TargetValue = Vector3.Zero; 111 CurrentValue = TargetValue = Vector3.Zero;
116 ErrorZeroThreshold = 0.001f; 112 ErrorZeroThreshold = 0.001f;
117 } 113 }
118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 114 public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency)
119 : this(useName) 115 : this(useName)
120 { 116 {
121 TimeScale = timeScale; 117 TimeScale = timeScale;
122 TargetValueDecayTimeScale = decayTimeScale; 118 TargetValueDecayTimeScale = decayTimeScale;
123 FrictionTimescale = frictionTimeScale;
124 Efficiency = efficiency; 119 Efficiency = efficiency;
125 CurrentValue = TargetValue = Vector3.Zero; 120 CurrentValue = TargetValue = Vector3.Zero;
126 } 121 }
@@ -138,7 +133,8 @@ public class BSVMotor : BSMotor
138 CurrentValue = TargetValue = Vector3.Zero; 133 CurrentValue = TargetValue = Vector3.Zero;
139 } 134 }
140 135
141 // Compute the next step and return the new current value 136 // Compute the next step and return the new current value.
137 // Returns the correction needed to move 'current' to 'target'.
142 public virtual Vector3 Step(float timeStep) 138 public virtual Vector3 Step(float timeStep)
143 { 139 {
144 if (!Enabled) return TargetValue; 140 if (!Enabled) return TargetValue;
@@ -148,9 +144,9 @@ public class BSVMotor : BSMotor
148 144
149 Vector3 correction = Vector3.Zero; 145 Vector3 correction = Vector3.Zero;
150 Vector3 error = TargetValue - CurrentValue; 146 Vector3 error = TargetValue - CurrentValue;
151 if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) 147 if (!ErrorIsZero(error))
152 { 148 {
153 correction = Step(timeStep, error); 149 correction = StepError(timeStep, error);
154 150
155 CurrentValue += correction; 151 CurrentValue += correction;
156 152
@@ -163,44 +159,43 @@ public class BSVMotor : BSMotor
163 TargetValue *= (1f - decayFactor); 159 TargetValue *= (1f - decayFactor);
164 } 160 }
165 161
166 // The amount we can correct the error is reduced by the friction
167 Vector3 frictionFactor = Vector3.Zero;
168 if (FrictionTimescale != BSMotor.InfiniteVector)
169 {
170 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
171 // Individual friction components can be 'infinite' so compute each separately.
172 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
173 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
174 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
175 frictionFactor *= timeStep;
176 CurrentValue *= (Vector3.One - frictionFactor);
177 }
178
179 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", 162 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
180 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, 163 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
181 timeStep, error, correction); 164 timeStep, error, correction);
182 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", 165 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
183 BSScene.DetailLogZero, UseName, 166 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
184 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
185 TargetValue, CurrentValue);
186 } 167 }
187 else 168 else
188 { 169 {
189 // Difference between what we have and target is small. Motor is done. 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 }
190 CurrentValue = TargetValue; 177 CurrentValue = TargetValue;
191 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", 178 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
192 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); 179 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
193 } 180 }
181 LastError = error;
194 182
195 return CurrentValue; 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);
196 } 190 }
197 public virtual Vector3 Step(float timeStep, Vector3 error) 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)
198 { 194 {
199 if (!Enabled) return Vector3.Zero; 195 if (!Enabled) return Vector3.Zero;
200 196
201 LastError = error;
202 Vector3 returnCorrection = Vector3.Zero; 197 Vector3 returnCorrection = Vector3.Zero;
203 if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) 198 if (!ErrorIsZero(error))
204 { 199 {
205 // correction = error / secondsItShouldTakeToCorrect 200 // correction = error / secondsItShouldTakeToCorrect
206 Vector3 correctionAmount; 201 Vector3 correctionAmount;
@@ -222,57 +217,155 @@ public class BSVMotor : BSMotor
222 // maximum number of outputs to generate. 217 // maximum number of outputs to generate.
223 int maxOutput = 50; 218 int maxOutput = 50;
224 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); 219 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
225 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", 220 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}",
226 BSScene.DetailLogZero, UseName, 221 BSScene.DetailLogZero, UseName,
227 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, 222 TimeScale, TargetValueDecayTimeScale, Efficiency,
228 CurrentValue, TargetValue); 223 CurrentValue, TargetValue);
229 224
230 LastError = BSMotor.InfiniteVector; 225 LastError = BSMotor.InfiniteVector;
231 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) 226 while (maxOutput-- > 0 && !ErrorIsZero())
232 { 227 {
233 Vector3 lastStep = Step(timeStep); 228 Vector3 lastStep = Step(timeStep);
234 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", 229 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
235 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); 230 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
236 } 231 }
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); 232 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
238 233
239 234
240 } 235 }
241 236
242 public override string ToString() 237 public override string ToString()
243 { 238 {
244 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", 239 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
245 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); 240 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
246 } 241 }
247} 242}
248 243
244// ============================================================================
245// ============================================================================
249public class BSFMotor : BSMotor 246public class BSFMotor : BSMotor
250{ 247{
251 public float TimeScale { get; set; } 248 public virtual float TimeScale { get; set; }
252 public float DecayTimeScale { get; set; } 249 public virtual float TargetValueDecayTimeScale { get; set; }
253 public float Friction { get; set; } 250 public virtual float Efficiency { get; set; }
254 public 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; }
255 257
256 public float Target { get; private set; } 258 public virtual bool ErrorIsZero()
257 public float CurrentValue { get; private set; } 259 {
260 return ErrorIsZero(LastError);
261 }
262 public virtual bool ErrorIsZero(float err)
263 {
264 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
265 }
258 266
259 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) 267 public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency)
260 : base(useName) 268 : base(useName)
261 { 269 {
270 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
271 Efficiency = 1f;
272 CurrentValue = TargetValue = 0f;
273 ErrorZeroThreshold = 0.01f;
262 } 274 }
263 public void SetCurrent(float target) 275 public void SetCurrent(float current)
264 { 276 {
277 CurrentValue = current;
265 } 278 }
266 public void SetTarget(float target) 279 public void SetTarget(float target)
267 { 280 {
281 TargetValue = target;
282 }
283 public override void Zero()
284 {
285 base.Zero();
286 CurrentValue = TargetValue = 0f;
268 } 287 }
288
269 public virtual float Step(float timeStep) 289 public virtual float Step(float timeStep)
270 { 290 {
271 return 0f; 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;
272 } 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
273} 364}
274 365
275// Proportional, Integral, Derivitive Motor 366// ============================================================================
367// ============================================================================
368// Proportional, Integral, Derivitive ("PID") Motor
276// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. 369// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
277public class BSPIDVMotor : BSVMotor 370public class BSPIDVMotor : BSVMotor
278{ 371{
@@ -281,6 +374,11 @@ public class BSPIDVMotor : BSVMotor
281 public Vector3 integralFactor { get; set; } 374 public Vector3 integralFactor { get; set; }
282 public Vector3 derivFactor { get; set; } 375 public Vector3 derivFactor { get; set; }
283 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
284 // Arbritrary factor range. 382 // Arbritrary factor range.
285 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. 383 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
286 public float EfficiencyHigh = 0.4f; 384 public float EfficiencyHigh = 0.4f;
@@ -295,6 +393,7 @@ public class BSPIDVMotor : BSVMotor
295 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); 393 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
296 integralFactor = new Vector3(1.00f, 1.00f, 1.00f); 394 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
297 derivFactor = 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);
298 RunningIntegration = Vector3.Zero; 397 RunningIntegration = Vector3.Zero;
299 LastError = Vector3.Zero; 398 LastError = Vector3.Zero;
300 } 399 }
@@ -310,20 +409,24 @@ public class BSPIDVMotor : BSVMotor
310 set 409 set
311 { 410 {
312 base.Efficiency = Util.Clamp(value, 0f, 1f); 411 base.Efficiency = Util.Clamp(value, 0f, 1f);
412
313 // Compute factors based on efficiency. 413 // Compute factors based on efficiency.
314 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. 414 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
315 // If efficiency is low (0f), use a factor value that overcorrects. 415 // If efficiency is low (0f), use a factor value that overcorrects.
316 // TODO: might want to vary contribution of different factor depending on efficiency. 416 // TODO: might want to vary contribution of different factor depending on efficiency.
317 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; 417 // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
318 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; 418 float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
419
319 proportionFactor = new Vector3(factor, factor, factor); 420 proportionFactor = new Vector3(factor, factor, factor);
320 integralFactor = new Vector3(factor, factor, factor); 421 integralFactor = new Vector3(factor, factor, factor);
321 derivFactor = 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);
322 } 425 }
323 } 426 }
324 427
325 // Ignore Current and Target Values and just advance the PID computation on this error. 428 // Advance the PID computation on this error.
326 public override Vector3 Step(float timeStep, Vector3 error) 429 public override Vector3 StepError(float timeStep, Vector3 error)
327 { 430 {
328 if (!Enabled) return Vector3.Zero; 431 if (!Enabled) return Vector3.Zero;
329 432
@@ -331,15 +434,16 @@ public class BSPIDVMotor : BSVMotor
331 RunningIntegration += error * timeStep; 434 RunningIntegration += error * timeStep;
332 435
333 // A simple derivitive is the rate of change from the last error. 436 // A simple derivitive is the rate of change from the last error.
334 Vector3 derivFactor = (error - LastError) * timeStep; 437 Vector3 derivitive = (error - LastError) * timeStep;
335 LastError = error; 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 ;
336 444
337 // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) 445 MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}",
338 Vector3 ret = -( 446 BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret);
339 error * proportionFactor
340 + RunningIntegration * integralFactor
341 + derivFactor * derivFactor
342 );
343 447
344 return ret; 448 return ret;
345 } 449 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
index e4fecc3..42fc11b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
@@ -30,15 +30,14 @@ using System.Text;
30 30
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Framework; 32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules; 33using OpenSim.Region.PhysicsModules.SharedBase;
34using OpenSim.Region.Physics.Manager;
35 34
36using Nini.Config; 35using Nini.Config;
37using log4net; 36using log4net;
38 37
39using OpenMetaverse; 38using OpenMetaverse;
40 39
41namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.PhysicsModule.BulletS
42{ 41{
43public sealed class BSTerrainHeightmap : BSTerrainPhys 42public sealed class BSTerrainHeightmap : BSTerrainPhys
44{ 43{
@@ -58,7 +57,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
58 { 57 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; 58 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 } 59 }
61 m_mapInfo = new BulletHMapInfo(id, initialMap); 60 m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y);
62 m_mapInfo.minCoords = minTerrainCoords; 61 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords; 62 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase; 63 m_mapInfo.terrainRegionBase = TerrainBase;
@@ -68,11 +67,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
68 67
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z 68 // 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). 69 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 70 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords) 71 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id) 72 : base(physicsScene, regionBase, id)
74 { 73 {
75 m_mapInfo = new BulletHMapInfo(id, initialMap); 74 m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y);
76 m_mapInfo.minCoords = minCoords; 75 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords; 76 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z; 77 m_mapInfo.minZ = minCoords.Z;
@@ -92,7 +91,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
92 private void BuildHeightmapTerrain() 91 private void BuildHeightmapTerrain()
93 { 92 {
94 // Create the terrain shape from the mapInfo 93 // Create the terrain shape from the mapInfo
95 m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, 94 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, 95 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); 96 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98 97
@@ -103,26 +102,25 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); 102 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); 103 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
105 104
106 m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, 105 m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
107 m_mapInfo.ID, centerPos, Quaternion.Identity); 106 m_mapInfo.ID, centerPos, Quaternion.Identity);
108 107
109 // Set current terrain attributes 108 // Set current terrain attributes
110 PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); 109 m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
111 PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); 110 m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
112 PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); 111 m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
113 PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); 112 m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
113
114 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
114 115
115 // Return the new terrain to the world of physical objects 116 // Return the new terrain to the world of physical objects
116 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); 117 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
117 118
118 // redo its bounding box now that it is in the world 119 // redo its bounding box now that it is in the world
119 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); 120 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
120
121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
122 m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene);
123 121
124 // Make it so the terrain will not move or be considered for movement. 122 // Make it so the terrain will not move or be considered for movement.
125 PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); 123 m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
126 124
127 return; 125 return;
128 } 126 }
@@ -134,9 +132,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
134 { 132 {
135 if (m_mapInfo.terrainBody.HasPhysicalBody) 133 if (m_mapInfo.terrainBody.HasPhysicalBody)
136 { 134 {
137 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); 135 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
138 // Frees both the body and the shape. 136 // Frees both the body and the shape.
139 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); 137 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
140 } 138 }
141 } 139 }
142 m_mapInfo = null; 140 m_mapInfo = null;
@@ -155,7 +153,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
155 catch 153 catch
156 { 154 {
157 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 155 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
158 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", 156 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
159 LogHeader, m_mapInfo.terrainRegionBase, pos); 157 LogHeader, m_mapInfo.terrainRegionBase, pos);
160 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 158 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
161 } 159 }
@@ -165,7 +163,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
165 // The passed position is relative to the base of the region. 163 // The passed position is relative to the base of the region.
166 public override float GetWaterLevelAtXYZ(Vector3 pos) 164 public override float GetWaterLevelAtXYZ(Vector3 pos)
167 { 165 {
168 return PhysicsScene.SimpleWaterLevel; 166 return m_physicsScene.SimpleWaterLevel;
169 } 167 }
170} 168}
171} 169}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
index 2e9db39..d11baa6 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -30,15 +30,14 @@ using System.Text;
30 30
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Framework; 32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules; 33using OpenSim.Region.PhysicsModules.SharedBase;
34using OpenSim.Region.Physics.Manager;
35 34
36using Nini.Config; 35using Nini.Config;
37using log4net; 36using log4net;
38 37
39using OpenMetaverse; 38using OpenMetaverse;
40 39
41namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.PhysicsModule.BulletS
42{ 41{
43 42
44// The physical implementation of the terrain is wrapped in this class. 43// The physical implementation of the terrain is wrapped in this class.
@@ -50,14 +49,14 @@ public abstract class BSTerrainPhys : IDisposable
50 Mesh = 1 49 Mesh = 1
51 } 50 }
52 51
53 public BSScene PhysicsScene { get; private set; } 52 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this. 53 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; } 54 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; } 55 public uint ID { get; private set; }
57 56
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) 57 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 { 58 {
60 PhysicsScene = physicsScene; 59 m_physicsScene = physicsScene;
61 TerrainBase = regionBase; 60 TerrainBase = regionBase;
62 ID = id; 61 ID = id;
63 } 62 }
@@ -86,7 +85,7 @@ public sealed class BSTerrainManager : IDisposable
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 85 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 86
88 // The scene that I am part of 87 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; } 88 private BSScene m_physicsScene { get; set; }
90 89
91 // The ground plane created to keep thing from falling to infinity. 90 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane; 91 private BulletBody m_groundPlane;
@@ -111,9 +110,11 @@ public sealed class BSTerrainManager : IDisposable
111 private Vector3 m_worldMax; 110 private Vector3 m_worldMax;
112 private PhysicsScene MegaRegionParentPhysicsScene { get; set; } 111 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
113 112
114 public BSTerrainManager(BSScene physicsScene) 113 public BSTerrainManager(BSScene physicsScene, Vector3 regionSize)
115 { 114 {
116 PhysicsScene = physicsScene; 115 m_physicsScene = physicsScene;
116 DefaultRegionSize = regionSize;
117
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); 118 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118 119
119 // Assume one region of default size 120 // Assume one region of default size
@@ -132,32 +133,39 @@ public sealed class BSTerrainManager : IDisposable
132 // safe to call Bullet in real time. We hope no one is moving prims around yet. 133 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain() 134 public void CreateInitialGroundPlaneAndTerrain()
134 { 135 {
136 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
135 // The ground plane is here to catch things that are trying to drop to negative infinity 137 // The ground plane is here to catch things that are trying to drop to negative infinity
136 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); 138 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, 139 Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane);
138 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); 140 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
141 BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity);
139 142
140 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
141 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
142 // Ground plane does not move
143 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
144 // Everything collides with the ground plane. 143 // Everything collides with the ground plane.
145 m_groundPlane.collisionType = CollisionType.Groundplane; 144 m_groundPlane.collisionType = CollisionType.Groundplane;
146 m_groundPlane.ApplyCollisionMask(PhysicsScene);
147 145
148 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 146 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
150 m_terrains.Add(Vector3.Zero, initialTerrain); 148
149 // Ground plane does not move
150 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
151
152 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
153 lock (m_terrains)
154 {
155 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
156 m_terrains.Add(Vector3.Zero, initialTerrain);
157 }
151 } 158 }
152 159
153 // Release all the terrain structures we might have allocated 160 // Release all the terrain structures we might have allocated
154 public void ReleaseGroundPlaneAndTerrain() 161 public void ReleaseGroundPlaneAndTerrain()
155 { 162 {
163 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
156 if (m_groundPlane.HasPhysicalBody) 164 if (m_groundPlane.HasPhysicalBody)
157 { 165 {
158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) 166 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
159 { 167 {
160 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); 168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
161 } 169 }
162 m_groundPlane.Clear(); 170 m_groundPlane.Clear();
163 } 171 }
@@ -183,7 +191,7 @@ public sealed class BSTerrainManager : IDisposable
183 float[] localHeightMap = heightMap; 191 float[] localHeightMap = heightMap;
184 // If there are multiple requests for changes to the same terrain between ticks, 192 // If there are multiple requests for changes to the same terrain between ticks,
185 // only do that last one. 193 // only do that last one.
186 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() 194 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
187 { 195 {
188 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 196 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
189 { 197 {
@@ -193,11 +201,9 @@ public sealed class BSTerrainManager : IDisposable
193 // the terrain is added to our parent 201 // the terrain is added to our parent
194 if (MegaRegionParentPhysicsScene is BSScene) 202 if (MegaRegionParentPhysicsScene is BSScene)
195 { 203 {
196 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 204 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
197 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 205 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
198 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( 206 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
199 BSScene.CHILDTERRAIN_ID, localHeightMap,
200 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
201 } 207 }
202 } 208 }
203 else 209 else
@@ -205,27 +211,34 @@ public sealed class BSTerrainManager : IDisposable
205 // If not doing the mega-prim thing, just change the terrain 211 // If not doing the mega-prim thing, just change the terrain
206 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 212 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
207 213
208 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, 214 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
210 } 215 }
211 }); 216 });
212 } 217 }
213 218
214 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain 219 // Another region is calling this region and passing a terrain.
220 // A region that is not the mega-region root will pass its terrain to the root region so the root region
221 // physics engine will have all the terrains.
222 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
223 {
224 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
225 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
226 {
227 UpdateTerrain(id, heightMap, minCoords, maxCoords);
228 });
229 }
230
231 // If called for terrain has has not been previously allocated, a new terrain will be built
215 // based on the passed information. The 'id' should be either the terrain id or 232 // based on the passed information. The 'id' should be either the terrain id or
216 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 233 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
217 // The latter feature is for creating child terrains for mega-regions. 234 // The latter feature is for creating child terrains for mega-regions.
218 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 235 // If there is an existing terrain body, a new
219 // terrain shape is created and added to the body. 236 // terrain shape is created and added to the body.
220 // This call is most often used to update the heightMap and parameters of the terrain. 237 // This call is most often used to update the heightMap and parameters of the terrain.
221 // (The above does suggest that some simplification/refactoring is in order.) 238 // (The above does suggest that some simplification/refactoring is in order.)
222 // Called during taint-time. 239 // Called during taint-time.
223 private void UpdateTerrain(uint id, float[] heightMap, 240 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
225 { 241 {
226 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
227 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
228
229 // Find high and low points of passed heightmap. 242 // Find high and low points of passed heightmap.
230 // The min and max passed in is usually the area objects can be in (maximum 243 // The min and max passed in is usually the area objects can be in (maximum
231 // object height, for instance). The terrain wants the bounding box for the 244 // object height, for instance). The terrain wants the bounding box for the
@@ -245,6 +258,9 @@ public sealed class BSTerrainManager : IDisposable
245 minCoords.Z = minZ; 258 minCoords.Z = minZ;
246 maxCoords.Z = maxZ; 259 maxCoords.Z = maxZ;
247 260
261 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
262 BSScene.DetailLogZero, id, minCoords, maxCoords);
263
248 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 264 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
249 265
250 lock (m_terrains) 266 lock (m_terrains)
@@ -253,8 +269,8 @@ public sealed class BSTerrainManager : IDisposable
253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) 269 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
254 { 270 {
255 // There is already a terrain in this spot. Free the old and build the new. 271 // There is already a terrain in this spot. Free the old and build the new.
256 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 272 DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); 273 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords);
258 274
259 // Remove old terrain from the collection 275 // Remove old terrain from the collection
260 m_terrains.Remove(terrainRegionBase); 276 m_terrains.Remove(terrainRegionBase);
@@ -263,6 +279,7 @@ public sealed class BSTerrainManager : IDisposable
263 279
264 if (MegaRegionParentPhysicsScene == null) 280 if (MegaRegionParentPhysicsScene == null)
265 { 281 {
282 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
266 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 283 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
267 m_terrains.Add(terrainRegionBase, newTerrainPhys); 284 m_terrains.Add(terrainRegionBase, newTerrainPhys);
268 285
@@ -291,8 +308,8 @@ public sealed class BSTerrainManager : IDisposable
291 if (newTerrainID >= BSScene.CHILDTERRAIN_ID) 308 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
292 newTerrainID = ++m_terrainCount; 309 newTerrainID = ++m_terrainCount;
293 310
294 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", 311 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
295 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 312 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
296 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 313 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
297 m_terrains.Add(terrainRegionBase, newTerrainPhys); 314 m_terrains.Add(terrainRegionBase, newTerrainPhys);
298 315
@@ -304,26 +321,26 @@ public sealed class BSTerrainManager : IDisposable
304 // TODO: redo terrain implementation selection to allow other base types than heightMap. 321 // TODO: redo terrain implementation selection to allow other base types than heightMap.
305 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) 322 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
306 { 323 {
307 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 324 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
308 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 325 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
309 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); 326 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
310 BSTerrainPhys newTerrainPhys = null; 327 BSTerrainPhys newTerrainPhys = null;
311 switch ((int)BSParam.TerrainImplementation) 328 switch ((int)BSParam.TerrainImplementation)
312 { 329 {
313 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 330 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
314 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 331 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
315 heightMap, minCoords, maxCoords); 332 heightMap, minCoords, maxCoords);
316 break; 333 break;
317 case (int)BSTerrainPhys.TerrainImplementation.Mesh: 334 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
318 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, 335 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
319 heightMap, minCoords, maxCoords); 336 heightMap, minCoords, maxCoords);
320 break; 337 break;
321 default: 338 default:
322 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 339 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
323 LogHeader, 340 LogHeader,
324 (int)BSParam.TerrainImplementation, 341 (int)BSParam.TerrainImplementation,
325 BSParam.TerrainImplementation, 342 BSParam.TerrainImplementation,
326 PhysicsScene.RegionName, terrainRegionBase); 343 m_physicsScene.RegionName, terrainRegionBase);
327 break; 344 break;
328 } 345 }
329 return newTerrainPhys; 346 return newTerrainPhys;
@@ -337,6 +354,64 @@ public sealed class BSTerrainManager : IDisposable
337 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); 354 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
338 } 355 }
339 356
357 // Return a new position that is over known terrain if the position is outside our terrain.
358 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
359 {
360 float edgeEpsilon = 0.1f;
361
362 Vector3 ret = pPos;
363
364 // First, base addresses are never negative so correct for that possible problem.
365 if (ret.X < 0f || ret.Y < 0f)
366 {
367 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
368 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
369 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
370 BSScene.DetailLogZero, pPos, ret);
371 }
372
373 // Can't do this function if we don't know about any terrain.
374 if (m_terrains.Count == 0)
375 return ret;
376
377 int loopPrevention = 10;
378 Vector3 terrainBaseXYZ;
379 BSTerrainPhys physTerrain;
380 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
381 {
382 // The passed position is not within a known terrain area.
383 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
384
385 // Must be off the top of a region. Find an adjacent region to move into.
386 // The returned terrain is always 'lower'. That is, closer to <0,0>.
387 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
388
389 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
390 {
391 // moving down into a new region in the X dimension. New position will be the max in the new base.
392 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
393 }
394 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
395 {
396 // moving down into a new region in the X dimension. New position will be the max in the new base.
397 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
398 }
399 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
400 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
401
402 if (loopPrevention-- < 0f)
403 {
404 // The 'while' is a little dangerous so this prevents looping forever if the
405 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
406 // the list of terrains is in transition.
407 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
408 break;
409 }
410 }
411
412 return ret;
413 }
414
340 // Given an X and Y, find the height of the terrain. 415 // Given an X and Y, find the height of the terrain.
341 // Since we could be handling multiple terrains for a mega-region, 416 // Since we could be handling multiple terrains for a mega-region,
342 // the base of the region is calcuated assuming all regions are 417 // the base of the region is calcuated assuming all regions are
@@ -368,8 +443,8 @@ public sealed class BSTerrainManager : IDisposable
368 } 443 }
369 else 444 else
370 { 445 {
371 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 446 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
372 LogHeader, PhysicsScene.RegionName, tX, tY); 447 LogHeader, m_physicsScene.RegionName, tX, tY);
373 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", 448 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
374 BSScene.DetailLogZero, pos, terrainBaseXYZ); 449 BSScene.DetailLogZero, pos, terrainBaseXYZ);
375 } 450 }
@@ -390,8 +465,8 @@ public sealed class BSTerrainManager : IDisposable
390 } 465 }
391 else 466 else
392 { 467 {
393 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", 468 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
394 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); 469 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
395 } 470 }
396 return ret; 471 return ret;
397 } 472 }
@@ -400,18 +475,69 @@ public sealed class BSTerrainManager : IDisposable
400 // the descriptor class and the 'base' fo the addresses therein. 475 // the descriptor class and the 'base' fo the addresses therein.
401 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) 476 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
402 { 477 {
403 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 478 bool ret = false;
404 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 479
405 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); 480 Vector3 terrainBaseXYZ = Vector3.Zero;
481 if (pos.X < 0f || pos.Y < 0f)
482 {
483 // We don't handle negative addresses so just make up a base that will not be found.
484 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
485 }
486 else
487 {
488 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
489 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
490 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
491 }
406 492
407 BSTerrainPhys physTerrain = null; 493 BSTerrainPhys physTerrain = null;
408 lock (m_terrains) 494 lock (m_terrains)
409 { 495 {
410 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); 496 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
411 } 497 }
412 outTerrainBase = terrainBaseXYZ; 498 outTerrainBase = terrainBaseXYZ;
413 outPhysTerrain = physTerrain; 499 outPhysTerrain = physTerrain;
414 return (physTerrain != null); 500 return ret;
501 }
502
503 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
504 // this one. Usually used to return an out of bounds object to a known place.
505 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
506 {
507 Vector3 ret = pTerrainBase;
508
509 // Can't do this function if we don't know about any terrain.
510 if (m_terrains.Count == 0)
511 return ret;
512
513 // Just some sanity
514 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
515 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
516 ret.Z = 0f;
517
518 lock (m_terrains)
519 {
520 // Once down to the <0,0> region, we have to be done.
521 while (ret.X > 0f || ret.Y > 0f)
522 {
523 if (ret.X > 0f)
524 {
525 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
526 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
527 if (m_terrains.ContainsKey(ret))
528 break;
529 }
530 if (ret.Y > 0f)
531 {
532 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
533 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
534 if (m_terrains.ContainsKey(ret))
535 break;
536 }
537 }
538 }
539
540 return ret;
415 } 541 }
416 542
417 // Although no one seems to check this, I do support combining. 543 // Although no one seems to check this, I do support combining.
@@ -452,7 +578,7 @@ public sealed class BSTerrainManager : IDisposable
452 578
453 private void DetailLog(string msg, params Object[] args) 579 private void DetailLog(string msg, params Object[] args)
454 { 580 {
455 PhysicsScene.PhysicsLogging.Write(msg, args); 581 m_physicsScene.PhysicsLogging.Write(msg, args);
456 } 582 }
457} 583}
458} 584}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
index 662dd68..3329395 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
@@ -29,7 +29,7 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OMV = OpenMetaverse; 30using OMV = OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34// Classes to allow some type checking for the API 34// Classes to allow some type checking for the API
35// These hold pointers to allocated objects in the unmanaged space. 35// These hold pointers to allocated objects in the unmanaged space.
@@ -104,18 +104,20 @@ public class BulletShape
104{ 104{
105 public BulletShape() 105 public BulletShape()
106 { 106 {
107 type = BSPhysicsShapeType.SHAPE_UNKNOWN; 107 shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; 108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false; 109 isNativeShape = false;
110 } 110 }
111 public BSPhysicsShapeType type; 111 public BSPhysicsShapeType shapeType;
112 public System.UInt64 shapeKey; 112 public System.UInt64 shapeKey;
113 public bool isNativeShape; 113 public bool isNativeShape;
114 114
115 public virtual void Clear() { } 115 public virtual void Clear() { }
116 public virtual bool HasPhysicalShape { get { return false; } } 116 public virtual bool HasPhysicalShape { get { return false; } }
117
117 // Make another reference to this physical object. 118 // Make another reference to this physical object.
118 public virtual BulletShape Clone() { return new BulletShape(); } 119 public virtual BulletShape Clone() { return new BulletShape(); }
120
119 // Return 'true' if this and other refer to the same physical object 121 // Return 'true' if this and other refer to the same physical object
120 public virtual bool ReferenceSame(BulletShape xx) { return false; } 122 public virtual bool ReferenceSame(BulletShape xx) { return false; }
121 123
@@ -131,7 +133,7 @@ public class BulletShape
131 buff.Append("<p="); 133 buff.Append("<p=");
132 buff.Append(AddrString); 134 buff.Append(AddrString);
133 buff.Append(",s="); 135 buff.Append(",s=");
134 buff.Append(type.ToString()); 136 buff.Append(shapeType.ToString());
135 buff.Append(",k="); 137 buff.Append(",k=");
136 buff.Append(shapeKey.ToString("X")); 138 buff.Append(shapeKey.ToString("X"));
137 buff.Append(",n="); 139 buff.Append(",n=");
@@ -163,14 +165,15 @@ public class BulletConstraint
163// than making copies. 165// than making copies.
164public class BulletHMapInfo 166public class BulletHMapInfo
165{ 167{
166 public BulletHMapInfo(uint id, float[] hm) { 168 public BulletHMapInfo(uint id, float[] hm, float pSizeX, float pSizeY) {
167 ID = id; 169 ID = id;
168 heightMap = hm; 170 heightMap = hm;
169 terrainRegionBase = OMV.Vector3.Zero; 171 terrainRegionBase = OMV.Vector3.Zero;
170 minCoords = new OMV.Vector3(100f, 100f, 25f); 172 minCoords = new OMV.Vector3(100f, 100f, 25f);
171 maxCoords = new OMV.Vector3(101f, 101f, 26f); 173 maxCoords = new OMV.Vector3(101f, 101f, 26f);
172 minZ = maxZ = 0f; 174 minZ = maxZ = 0f;
173 sizeX = sizeY = 256f; 175 sizeX = pSizeX;
176 sizeY = pSizeY;
174 } 177 }
175 public uint ID; 178 public uint ID;
176 public float[] heightMap; 179 public float[] heightMap;
@@ -187,6 +190,7 @@ public class BulletHMapInfo
187public enum CollisionType 190public enum CollisionType
188{ 191{
189 Avatar, 192 Avatar,
193 PhantomToOthersAvatar, // An avatar that it phantom to other avatars but not to anything else
190 Groundplane, 194 Groundplane,
191 Terrain, 195 Terrain,
192 Static, 196 Static,
@@ -215,45 +219,55 @@ public static class BulletSimData
215{ 219{
216 220
217// Map of collisionTypes to flags for collision groups and masks. 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//
218// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code 226// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
219// but, instead, use references to this dictionary. Finding and debugging 227// but, instead, use references to this dictionary. Finding and debugging
220// collision flag problems will be made easier. 228// collision flag problems will be made easier.
221public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks 229public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
222 = new Dictionary<CollisionType, CollisionTypeFilterGroup>() 230 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
223{ 231{
224 { CollisionType.Avatar, 232 { CollisionType.Avatar,
225 new CollisionTypeFilterGroup(CollisionType.Avatar, 233 new CollisionTypeFilterGroup(CollisionType.Avatar,
226 (uint)CollisionFilterGroups.BCharacterGroup, 234 (uint)CollisionFilterGroups.BCharacterGroup,
227 (uint)CollisionFilterGroups.BAllGroup) 235 (uint)(CollisionFilterGroups.BAllGroup))
228 }, 236 },
229 { CollisionType.Groundplane, 237 { CollisionType.PhantomToOthersAvatar,
230 new CollisionTypeFilterGroup(CollisionType.Groundplane, 238 new CollisionTypeFilterGroup(CollisionType.PhantomToOthersAvatar,
231 (uint)CollisionFilterGroups.BGroundPlaneGroup, 239 (uint)CollisionFilterGroups.BCharacterGroup,
232 (uint)CollisionFilterGroups.BAllGroup) 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))
233 }, 247 },
234 { CollisionType.Terrain, 248 { CollisionType.Terrain,
235 new CollisionTypeFilterGroup(CollisionType.Terrain, 249 new CollisionTypeFilterGroup(CollisionType.Terrain,
236 (uint)CollisionFilterGroups.BTerrainGroup, 250 (uint)CollisionFilterGroups.BTerrainGroup,
237 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) 251 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
238 }, 252 },
239 { CollisionType.Static, 253 { CollisionType.Static,
240 new CollisionTypeFilterGroup(CollisionType.Static, 254 new CollisionTypeFilterGroup(CollisionType.Static,
241 (uint)CollisionFilterGroups.BStaticGroup, 255 (uint)CollisionFilterGroups.BStaticGroup,
242 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 256 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
243 }, 257 },
244 { CollisionType.Dynamic, 258 { CollisionType.Dynamic,
245 new CollisionTypeFilterGroup(CollisionType.Dynamic, 259 new CollisionTypeFilterGroup(CollisionType.Dynamic,
246 (uint)CollisionFilterGroups.BSolidGroup, 260 (uint)CollisionFilterGroups.BSolidGroup,
247 (uint)(CollisionFilterGroups.BAllGroup)) 261 (uint)(CollisionFilterGroups.BAllGroup))
248 }, 262 },
249 { CollisionType.VolumeDetect, 263 { CollisionType.VolumeDetect,
250 new CollisionTypeFilterGroup(CollisionType.VolumeDetect, 264 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
251 (uint)CollisionFilterGroups.BSensorTrigger, 265 (uint)CollisionFilterGroups.BSensorTrigger,
252 (uint)(~CollisionFilterGroups.BSensorTrigger)) 266 (uint)(~CollisionFilterGroups.BSensorTrigger))
253 }, 267 },
254 { CollisionType.LinksetChild, 268 { CollisionType.LinksetChild,
255 new CollisionTypeFilterGroup(CollisionType.LinksetChild, 269 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
256 (uint)CollisionFilterGroups.BLinksetChildGroup, 270 (uint)CollisionFilterGroups.BLinksetChildGroup,
257 (uint)(CollisionFilterGroups.BNoneGroup)) 271 (uint)(CollisionFilterGroups.BNoneGroup))
258 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 272 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
259 }, 273 },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
index a8a4ff5..0453376 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
@@ -1,93 +1,107 @@
1CURRENT PRIORITIES 1CURRENT PROBLEMS TO FIX AND/OR LOOK AT
2================================================= 2=================================================
3Redo BulletSimAPI to allow native C# implementation of Bullet option. 3Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass.
4Avatar movement 4 Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive?
5 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle 5 Negative buoyancy computed correctly
6 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) 6Center-of-gravity
7 avatar capsule rotation completed 7Computation of mesh mass. How done? How should it be done?
8llMoveToTarget
9Enable vehicle border crossings (at least as poorly as ODE) 8Enable vehicle border crossings (at least as poorly as ODE)
10 Terrain skirts 9 Terrain skirts
11 Avatar created in previous region and not new region when crossing border 10 Avatar created in previous region and not new region when crossing border
12 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) 11 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
13Vehicle movement on terrain smoothness 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.
14Vehicle script tuning/debugging 28Vehicle script tuning/debugging
15 Avanti speed script 29 Avanti speed script
16 Weapon shooter script 30 Weapon shooter script
17limitMotorUp calibration (more down?) 31Move material definitions (friction, ...) into simulator.
18Boats float low in the water 32osGetPhysicsEngineVerion() and create a version code for the C++ DLL
19Add material densities to the material types. 33One sided meshes? Should terrain be built into a closed shape?
20 34 When meshes get partially wedged into the terrain, they cannot push themselves out.
21CRASHES 35 It is possible that Bullet processes collisions whether entering or leaving a mesh.
22================================================= 36 Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869
2320121129.1411: editting/moving phys object across region boundries causes crash 37Small physical objects do not interact correctly
24 getPos-> btRigidBody::upcast -> getBodyType -> BOOM 38 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
2520121128.1600: mesh object not rezzing (no physics mesh). 39 The chain will fall apart and pairs will dance around on ground
26 Causes many errors. Doesn't stop after first error with box shape. 40 Chains of 1x1x.2 will stay connected but will dance.
27 Eventually crashes when deleting the object. 41 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
2820121206.1434: rez Sam-pan into OSGrid BulletSim11 region
29 Immediate simulator crash. Mono does not output any stacktrace and
30 log just stops after reporting taint-time linking of the linkset.
31 42
32VEHICLES TODO LIST: 43VEHICLES TODO LIST:
33================================================= 44=================================================
34Angular motor direction is global coordinates rather than local coordinates 45LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
35Border crossing with linked vehicle causes crash 46 What are the limits in SL?
36Vehicles (Move smoothly) 47 Same for other velocity settings.
37Add vehicle collisions so IsColliding is properly reported. 48UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
38 Needed for banking, limitMotorUp, movementLimiting, ... 49 https://github.com/UbitUmarov/Ubit-opensim
39VehicleAddForce is not scaled by the simulation step but it is only
40 applied for one step. Should it be scaled?
41Some vehicles should not be able to turn if no speed or off ground. 50Some vehicles should not be able to turn if no speed or off ground.
42Cannot edit/move a vehicle being ridden: it jumps back to the origional position. 51Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
43Neb car jiggling left and right 52Neb car jiggling left and right
44 Happens on terrain and any other mesh object. Flat cubes are much smoother. 53 Happens on terrain and any other mesh object. Flat cubes are much smoother.
45 This has been reduced but not eliminated. 54 This has been reduced but not eliminated.
46Implement referenceFrame for all the motion routines. 55Implement referenceFrame for all the motion routines.
47Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
48 Verify that angular motion specified around Z moves in the vehicle coordinates.
49Verify llGetVel() is returning a smooth and good value for vehicle movement. 56Verify llGetVel() is returning a smooth and good value for vehicle movement.
50llGetVel() should return the root's velocity if requested in a child prim. 57llGetVel() should return the root's velocity if requested in a child prim.
51Implement function efficiency for lineaar and angular motion. 58Implement function efficiency for lineaar and angular motion.
52After getting off a vehicle, the root prim is phantom (can be walked through)
53 Need to force a position update for the root prim after compound shape destruction
54Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) 59Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
55For limitMotorUp, use raycast down to find if vehicle is in the air.
56Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). 60Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
57 A kludge that isn't fixing the real problem of Bullet adding extra motion. 61 A kludge that isn't fixing the real problem of Bullet adding extra motion.
58Incorporate inter-relationship of angular corrections. For instance, angularDeflection 62Incorporate inter-relationship of angular corrections. For instance, angularDeflection
59 and angularMotorUp will compute same X or Y correction. When added together 63 and angularMotorUp will compute same X or Y correction. When added together
60 creates over-correction and over-shoot and wabbling. 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?
61 68
62BULLETSIM TODO LIST: 69GENERAL TODO LIST:
63================================================= 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
64Implement an avatar mesh shape. The Bullet capsule is way too limited. 89Implement an avatar mesh shape. The Bullet capsule is way too limited.
65 Consider just hand creating a vertex/index array in a new BSShapeAvatar. 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.
66Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. 92Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
67Duplicating a physical prim causes old prim to jump away 93Duplicating a physical prim causes old prim to jump away
68 Dup a phys prim and the original become unselected and thus interacts w/ selected prim. 94 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
69Scenes with hundred of thousands of static objects take a lot of physics CPU time. 95Scenes with hundred of thousands of static objects take a lot of physics CPU time.
70BSPrim.Force should set a continious force on the prim. The force should be
71 applied each tick. Some limits?
72Gun sending shooter flying. 96Gun sending shooter flying.
73Collision margin (gap between physical objects lying on each other) 97Collision margin (gap between physical objects lying on each other)
74Boundry checking (crashes related to crossing boundry) 98Boundry checking (crashes related to crossing boundry)
75 Add check for border edge position for avatars and objects. 99 Add check for border edge position for avatars and objects.
76 Verify the events are created for border crossings. 100 Verify the events are created for border crossings.
77Avatar rotation (check out changes to ScenePresence for physical rotation)
78Avatar running (what does phys engine need to do?)
79Small physical objects do not interact correctly
80 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
81 The chain will fall apart and pairs will dance around on ground
82 Chains of 1x1x.2 will stay connected but will dance.
83 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
84Add PID motor for avatar movement (slow to stop, ...)
85setForce should set a constant force. Different than AddImpulse.
86Implement raycast.
87Implement ShapeCollection.Dispose() 101Implement ShapeCollection.Dispose()
88Implement water as a plain so raycasting and collisions can happen with same. 102Implement water as a plain or mesh so raycasting and collisions can happen with same.
89Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE 103Add collision penetration return
90 Also osGetPhysicsEngineVerion() maybe. 104 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
91Linkset.Position and Linkset.Orientation requre rewrite to properly return 105Linkset.Position and Linkset.Orientation requre rewrite to properly return
92 child position. LinksetConstraint acts like it's at taint time!! 106 child position. LinksetConstraint acts like it's at taint time!!
93Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) 107Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
@@ -99,14 +113,17 @@ Selecting and deselecting physical objects causes CPU processing time to jump
99Re-implement buoyancy as a separate force on the object rather than diddling gravity. 113Re-implement buoyancy as a separate force on the object rather than diddling gravity.
100 Register a pre-step event to add the force. 114 Register a pre-step event to add the force.
101More efficient memory usage when passing hull information from BSPrim to BulletSim 115More efficient memory usage when passing hull information from BSPrim to BulletSim
102Avatar movement motor check for zero or small movement. Somehow suppress small movements
103 when avatar has stopped and is just standing. Simple test for near zero has
104 the problem of preventing starting up (increase from zero) especially when falling.
105Physical and phantom will drop through the terrain 116Physical and phantom will drop through the terrain
106 117
107 118
108LINKSETS 119LINKSETS
109====================================================== 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
110Offset the center of the linkset to be the geometric center of all the prims 127Offset the center of the linkset to be the geometric center of all the prims
111 Not quite the same as the center-of-gravity 128 Not quite the same as the center-of-gravity
112Linksets should allow collisions to individual children 129Linksets should allow collisions to individual children
@@ -117,11 +134,9 @@ LinksetCompound: when one of the children changes orientation (like tires
117Verify/think through scripts in children of linksets. What do they reference 134Verify/think through scripts in children of linksets. What do they reference
118 and return when getting position, velocity, ... 135 and return when getting position, velocity, ...
119Confirm constraint linksets still work after making all the changes for compound linksets. 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
120Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. 138Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
121 For compound linksets, add ability to remove or reposition individual child shapes. 139 For compound linksets, add ability to remove or reposition individual child shapes.
122Disable activity of passive linkset children.
123 Since the linkset is a compound object, the old prims are left lying
124 around and need to be phantomized so they don't collide, ...
125Speed up creation of large physical linksets 140Speed up creation of large physical linksets
126 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. 141 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
127 REALLY bad for very large physical linksets (freezes the sim for many seconds). 142 REALLY bad for very large physical linksets (freezes the sim for many seconds).
@@ -131,25 +146,27 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint)
131 146
132MORE 147MORE
133====================================================== 148======================================================
134Test avatar walking up stairs. How does compare with SL. 149Compute avatar size and scale correctly. Now it is a bit off from the capsule size.
135 Radius of the capsule affects ability to climb edges. 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.
136Debounce avatar contact so legs don't keep folding up when standing. 157Debounce avatar contact so legs don't keep folding up when standing.
137Implement LSL physics controls. Like STATUS_ROTATE_X.
138Add border extensions to terrain to help region crossings and objects leaving region. 158Add border extensions to terrain to help region crossings and objects leaving region.
139Use a different capsule shape for avatar when sitting 159Use a different capsule shape for avatar when sitting
140 LL uses a pyrimidal shape scaled by the avatar's bounding box 160 LL uses a pyrimidal shape scaled by the avatar's bounding box
141 http://wiki.secondlife.com/wiki/File:Avmeshforms.png 161 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
142
143Performance test with lots of avatars. Can BulletSim support a thousand? 162Performance test with lots of avatars. Can BulletSim support a thousand?
144Optimize collisions in C++: only send up to the object subscribed to collisions. 163Optimize collisions in C++: only send up to the object subscribed to collisions.
145 Use collision subscription and remove the collsion(A,B) and collision(B,A) 164 Use collision subscription and remove the collsion(A,B) and collision(B,A)
146Check whether SimMotionState needs large if statement (see TODO). 165Check whether SimMotionState needs large if statement (see TODO).
147
148Implement 'top colliders' info. 166Implement 'top colliders' info.
149Avatar jump 167Avatar jump
150Performance measurement and changes to make quicker. 168Performance measurement and changes to make quicker.
151Implement detailed physics stats (GetStats()). 169Implement detailed physics stats (GetStats()).
152
153Measure performance improvement from hulls 170Measure performance improvement from hulls
154Test not using ghost objects for volume detect implementation. 171Test not using ghost objects for volume detect implementation.
155Performance of closures and delegates for taint processing 172Performance of closures and delegates for taint processing
@@ -157,9 +174,7 @@ Performance of closures and delegates for taint processing
157 Is any slowdown introduced by the existing implementation significant? 174 Is any slowdown introduced by the existing implementation significant?
158Is there are more efficient method of implementing pre and post step actions? 175Is there are more efficient method of implementing pre and post step actions?
159 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C 176 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
160
161Physics Arena central pyramid: why is one side permiable? 177Physics Arena central pyramid: why is one side permiable?
162
163In SL, perfect spheres don't seem to have rolling friction. Add special case. 178In SL, perfect spheres don't seem to have rolling friction. Add special case.
164Enforce physical parameter min/max: 179Enforce physical parameter min/max:
165 Gravity: [-1, 28] 180 Gravity: [-1, 28]
@@ -168,6 +183,7 @@ Enforce physical parameter min/max:
168 Restitution [0, 1] 183 Restitution [0, 1]
169 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test 184 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
170Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html 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
171 187
172INTERNAL IMPROVEMENT/CLEANUP 188INTERNAL IMPROVEMENT/CLEANUP
173================================================= 189=================================================
@@ -190,22 +206,19 @@ Generalize Dynamics and PID with standardized motors.
190Generalize Linkset and vehicles into PropertyManagers 206Generalize Linkset and vehicles into PropertyManagers
191 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies 207 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
192 Potentially add events for shape destruction, etc. 208 Potentially add events for shape destruction, etc.
193Complete implemention of preStepActions 209Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
194 Replace vehicle step call with prestep event. 210 BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc.
195 Is there a need for postStepActions? postStepTaints?
196Implement linkset by setting position of children when root updated. (LinksetManual) 211Implement linkset by setting position of children when root updated. (LinksetManual)
197 Linkset implementation using manual prim movement. 212 Linkset implementation using manual prim movement.
198LinkablePrim class? Would that simplify/centralize the linkset logic? 213LinkablePrim class? Would that simplify/centralize the linkset logic?
199BSScene.UpdateParameterSet() is broken. How to set params on objects? 214BSScene.UpdateParameterSet() is broken. How to set params on objects?
200Remove HeightmapInfo from terrain specification
201 Since C++ code does not need terrain height, this structure et al are not needed.
202Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will 215Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
203 bob at the water level. BSPrim.PositionSanityCheck(). 216 bob at the water level. BSPrim.PositionSanityCheck()
204Should taints check for existance or activeness of target? 217Should taints check for existance or activeness of target?
205 When destroying linksets/etc, taints can be generated for objects that are 218 When destroying linksets/etc, taints can be generated for objects that are
206 actually gone when the taint happens. Crashes don't happen because the taint closure 219 actually gone when the taint happens. Crashes don't happen because the taint closure
207 keeps the object from being freed, but that is just an accident. 220 keeps the object from being freed, but that is just an accident.
208 Possibly have and 'active' flag that is checked by the taint processor? 221 Possibly have an 'active' flag that is checked by the taint processor?
209Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) 222Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
210Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? 223Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
211There are TOO MANY interfaces from BulletSim core to Bullet itself 224There are TOO MANY interfaces from BulletSim core to Bullet itself
@@ -270,3 +283,97 @@ llSetBuoyancy() (DONE)
270 (Resolution: Bullet resets object gravity when added to world. Moved set gravity) 283 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
271Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) 284Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
272 (Resolution: set default density to 3.5 (from 60) which is closer to SL) 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/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
index 0d1db3b..698be39 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
@@ -1,6 +1,7 @@
1using System.Reflection; 1using System.Reflection;
2using System.Runtime.CompilerServices; 2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4using Mono.Addins;
4 5
5// General Information about an assembly is controlled through the following 6// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information 7// set of attributes. Change these attribute values to modify the information
@@ -29,5 +30,7 @@ using System.Runtime.InteropServices;
29// Build Number 30// Build Number
30// Revision 31// Revision
31// 32//
32[assembly: AssemblyVersion("0.7.5.*")] 33[assembly: AssemblyVersion("0.8.3.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 34
35[assembly: Addin("OpenSim.Region.PhysicsModule.BulletS", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]