aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs400
1 files changed, 269 insertions, 131 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..c215e3a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -66,9 +66,10 @@ public sealed class BSCharacter : BSPhysObject
66 private float _buoyancy; 66 private float _buoyancy;
67 67
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 68 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity). 69 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71 70
71 private BSVMotor _velocityMotor;
72
72 private OMV.Vector3 _PIDTarget; 73 private OMV.Vector3 _PIDTarget;
73 private bool _usePID; 74 private bool _usePID;
74 private float _PIDTau; 75 private float _PIDTau;
@@ -83,34 +84,36 @@ public sealed class BSCharacter : BSPhysObject
83 _physicsActorType = (int)ActorTypes.Agent; 84 _physicsActorType = (int)ActorTypes.Agent;
84 _position = pos; 85 _position = pos;
85 86
86 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
87 // replace with the default values.
88 _size = size;
89 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
90 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
91
92 _flying = isFlying; 87 _flying = isFlying;
93 _orientation = OMV.Quaternion.Identity; 88 _orientation = OMV.Quaternion.Identity;
94 _velocity = OMV.Vector3.Zero; 89 _velocity = OMV.Vector3.Zero;
95 _appliedVelocity = OMV.Vector3.Zero;
96 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
97 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 91 _currentFriction = BSParam.AvatarStandingFriction;
98 _avatarDensity = PhysicsScene.Params.avatarDensity; 92 _avatarDensity = BSParam.AvatarDensity;
99 93
100 // The dimensions of the avatar capsule are kept in the scale. 94 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
95 // replace with the default values.
96 _size = size;
97 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
98 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
99
100 // The dimensions of the physical capsule are kept in the scale.
101 // Physics creates a unit capsule which is scaled by the physics engine. 101 // Physics creates a unit capsule which is scaled by the physics engine.
102 ComputeAvatarScale(_size); 102 Scale = ComputeAvatarScale(_size);
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 103 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 104 ComputeAvatarVolumeAndMass();
105
106 SetupMovementMotor();
107
105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 108 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 109 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
107 110
108 // do actual create at taint time 111 // do actual creation in taint time
109 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 112 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
110 { 113 {
111 DetailLog("{0},BSCharacter.create,taint", LocalID); 114 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape 115 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); 116 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
114 117
115 SetPhysicalProperties(); 118 SetPhysicalProperties();
116 }); 119 });
@@ -120,54 +123,116 @@ public sealed class BSCharacter : BSPhysObject
120 // called when this character is being destroyed and the resources should be released 123 // called when this character is being destroyed and the resources should be released
121 public override void Destroy() 124 public override void Destroy()
122 { 125 {
126 base.Destroy();
127
123 DetailLog("{0},BSCharacter.Destroy", LocalID); 128 DetailLog("{0},BSCharacter.Destroy", LocalID);
124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 129 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
125 { 130 {
126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 131 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
132 PhysBody.Clear();
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 133 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
134 PhysShape.Clear();
128 }); 135 });
129 } 136 }
130 137
131 private void SetPhysicalProperties() 138 private void SetPhysicalProperties()
132 { 139 {
133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 140 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
134 141
135 ZeroMotion(true); 142 ZeroMotion(true);
136 ForcePosition = _position; 143 ForcePosition = _position;
144
137 // Set the velocity and compute the proper friction 145 // Set the velocity and compute the proper friction
146 _velocityMotor.Reset();
147 _velocityMotor.SetTarget(_velocity);
148 _velocityMotor.SetCurrent(_velocity);
138 ForceVelocity = _velocity; 149 ForceVelocity = _velocity;
139 150
140 // This will enable or disable the flying buoyancy of the avatar. 151 // This will enable or disable the flying buoyancy of the avatar.
141 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 152 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying; 153 Flying = _flying;
143 154
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); 155 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); 156 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 157 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 158 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
148 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 159 if (BSParam.CcdMotionThreshold > 0f)
149 { 160 {
150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 161 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 162 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
152 } 163 }
153 164
154 UpdatePhysicalMassProperties(RawMass); 165 UpdatePhysicalMassProperties(RawMass, false);
155 166
156 // Make so capsule does not fall over 167 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); 168 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
158 169
159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 170 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
160 171
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 172 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
162 173
163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 174 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); 175 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 176 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
166 177
167 // Do this after the object has been added to the world 178 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, 179 PhysBody.collisionType = CollisionType.Avatar;
169 (uint)CollisionFilterGroups.AvatarFilter, 180 PhysBody.ApplyCollisionMask(PhysicsScene);
170 (uint)CollisionFilterGroups.AvatarMask); 181 }
182
183 // The avatar's movement is controlled by this motor that speeds up and slows down
184 // the avatar seeking to reach the motor's target speed.
185 // This motor runs as a prestep action for the avatar so it will keep the avatar
186 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
187 private void SetupMovementMotor()
188 {
189
190 // Someday, use a PID motor for asymmetric speed up and slow down
191 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
192
193 // Infinite decay and timescale values so motor only changes current to target values.
194 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
195 0.2f, // time scale
196 BSMotor.Infinite, // decay time scale
197 BSMotor.InfiniteVector, // friction timescale
198 1f // efficiency
199 );
200 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
201
202 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
203 {
204 // TODO: Decide if the step parameters should be changed depending on the avatar's
205 // state (flying, colliding, ...). There is code in ODE to do this.
206
207 OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
208
209 // If falling, we keep the world's downward vector no matter what the other axis specify.
210 if (!Flying && !IsColliding)
211 {
212 stepVelocity.Z = _velocity.Z;
213 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
214 }
215
216 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
217 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
218
219 /*
220 // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user
221 float moveForceMagnitudeSquared = moveForce.LengthSquared();
222 if (moveForceMagnitudeSquared < 0.0001)
223 {
224 DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}",
225 LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce);
226 ForceVelocity = OMV.Vector3.Zero;
227 }
228 else
229 {
230 AddForce(moveForce, false, true);
231 }
232 */
233 // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
234 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
235 });
171 } 236 }
172 237
173 public override void RequestPhysicsterseUpdate() 238 public override void RequestPhysicsterseUpdate()
@@ -185,24 +250,31 @@ public sealed class BSCharacter : BSPhysObject
185 } 250 }
186 251
187 set { 252 set {
188 // When an avatar's size is set, only the height is changed.
189 _size = value; 253 _size = value;
190 ComputeAvatarScale(_size); 254 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
255 // replace with the default values.
256 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
257 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
258
259 Scale = ComputeAvatarScale(_size);
191 ComputeAvatarVolumeAndMass(); 260 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 261 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 262 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
194 263
195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 264 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
196 { 265 {
197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 266 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
198 UpdatePhysicalMassProperties(RawMass); 267 {
268 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
269 UpdatePhysicalMassProperties(RawMass, true);
270 // Make sure this change appears as a property update event
271 PhysicsScene.PE.PushUpdate(PhysBody);
272 }
199 }); 273 });
200 274
201 } 275 }
202 } 276 }
203 277
204 public override OMV.Vector3 Scale { get; set; }
205
206 public override PrimitiveBaseShape Shape 278 public override PrimitiveBaseShape Shape
207 { 279 {
208 set { BaseShape = value; } 280 set { BaseShape = value; }
@@ -236,7 +308,8 @@ public sealed class BSCharacter : BSPhysObject
236 // Zero some other properties directly into the physics engine 308 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 309 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 { 310 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 311 if (PhysBody.HasPhysicalBody)
312 PhysicsScene.PE.ClearAllForces(PhysBody);
240 }); 313 });
241 } 314 }
242 public override void ZeroAngularMotion(bool inTaintTime) 315 public override void ZeroAngularMotion(bool inTaintTime)
@@ -245,10 +318,13 @@ public sealed class BSCharacter : BSPhysObject
245 318
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 319 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 { 320 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 321 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 322 {
250 // The next also get rid of applied linear force but the linear velocity is untouched. 323 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
251 BulletSimAPI.ClearForces2(PhysBody.ptr); 324 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
325 // The next also get rid of applied linear force but the linear velocity is untouched.
326 PhysicsScene.PE.ClearForces(PhysBody);
327 }
252 }); 328 });
253 } 329 }
254 330
@@ -263,7 +339,7 @@ public sealed class BSCharacter : BSPhysObject
263 public override OMV.Vector3 Position { 339 public override OMV.Vector3 Position {
264 get { 340 get {
265 // Don't refetch the position because this function is called a zillion times 341 // Don't refetch the position because this function is called a zillion times
266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); 342 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
267 return _position; 343 return _position;
268 } 344 }
269 set { 345 set {
@@ -273,19 +349,20 @@ public sealed class BSCharacter : BSPhysObject
273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 349 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
274 { 350 {
275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 351 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 352 if (PhysBody.HasPhysicalBody)
353 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
277 }); 354 });
278 } 355 }
279 } 356 }
280 public override OMV.Vector3 ForcePosition { 357 public override OMV.Vector3 ForcePosition {
281 get { 358 get {
282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 359 _position = PhysicsScene.PE.GetPosition(PhysBody);
283 return _position; 360 return _position;
284 } 361 }
285 set { 362 set {
286 _position = value; 363 _position = value;
287 PositionSanityCheck(); 364 PositionSanityCheck();
288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 365 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
289 } 366 }
290 } 367 }
291 368
@@ -297,6 +374,15 @@ public sealed class BSCharacter : BSPhysObject
297 { 374 {
298 bool ret = false; 375 bool ret = false;
299 376
377 // TODO: check for out of bounds
378 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
379 {
380 // The character is out of the known/simulated area.
381 // Upper levels of code will handle the transition to other areas so, for
382 // the time, we just ignore the position.
383 return ret;
384 }
385
300 // If below the ground, move the avatar up 386 // If below the ground, move the avatar up
301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 387 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
302 if (Position.Z < terrainHeight) 388 if (Position.Z < terrainHeight)
@@ -307,7 +393,7 @@ public sealed class BSCharacter : BSPhysObject
307 } 393 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 394 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 395 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 396 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 397 if (Position.Z < waterHeight)
312 { 398 {
313 _position.Z = waterHeight; 399 _position.Z = waterHeight;
@@ -315,7 +401,6 @@ public sealed class BSCharacter : BSPhysObject
315 } 401 }
316 } 402 }
317 403
318 // TODO: check for out of bounds
319 return ret; 404 return ret;
320 } 405 }
321 406
@@ -332,7 +417,8 @@ public sealed class BSCharacter : BSPhysObject
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 { 418 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 419 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 420 if (PhysBody.HasPhysicalBody)
421 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
336 }); 422 });
337 ret = true; 423 ret = true;
338 } 424 }
@@ -345,10 +431,10 @@ public sealed class BSCharacter : BSPhysObject
345 public override float RawMass { 431 public override float RawMass {
346 get {return _mass; } 432 get {return _mass; }
347 } 433 }
348 public override void UpdatePhysicalMassProperties(float physMass) 434 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
349 { 435 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 436 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); 437 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
352 } 438 }
353 439
354 public override OMV.Vector3 Force { 440 public override OMV.Vector3 Force {
@@ -359,7 +445,8 @@ public sealed class BSCharacter : BSPhysObject
359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 445 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
360 { 446 {
361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 447 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 448 if (PhysBody.HasPhysicalBody)
449 PhysicsScene.PE.SetObjectForce(PhysBody, _force);
363 }); 450 });
364 } 451 }
365 } 452 }
@@ -376,6 +463,31 @@ public sealed class BSCharacter : BSPhysObject
376 463
377 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 464 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
378 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 465 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
466
467 // Sets the target in the motor. This starts the changing of the avatar's velocity.
468 public override OMV.Vector3 TargetVelocity
469 {
470 get
471 {
472 return _velocityMotor.TargetValue;
473 }
474 set
475 {
476 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
477 OMV.Vector3 targetVel = value;
478 if (_setAlwaysRun)
479 targetVel *= BSParam.AvatarAlwaysRunFactor;
480
481 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
482 {
483 _velocityMotor.Reset();
484 _velocityMotor.SetTarget(targetVel);
485 _velocityMotor.SetCurrent(_velocity);
486 _velocityMotor.Enabled = true;
487 });
488 }
489 }
490 // Directly setting velocity means this is what the user really wants now.
379 public override OMV.Vector3 Velocity { 491 public override OMV.Vector3 Velocity {
380 get { return _velocity; } 492 get { return _velocity; }
381 set { 493 set {
@@ -383,6 +495,12 @@ public sealed class BSCharacter : BSPhysObject
383 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 495 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
384 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 496 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
385 { 497 {
498 _velocityMotor.Reset();
499 _velocityMotor.SetCurrent(_velocity);
500 _velocityMotor.SetTarget(_velocity);
501 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
502 _velocityMotor.Enabled = false;
503
386 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 504 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
387 ForceVelocity = _velocity; 505 ForceVelocity = _velocity;
388 }); 506 });
@@ -391,30 +509,32 @@ public sealed class BSCharacter : BSPhysObject
391 public override OMV.Vector3 ForceVelocity { 509 public override OMV.Vector3 ForceVelocity {
392 get { return _velocity; } 510 get { return _velocity; }
393 set { 511 set {
512 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
513
514 _velocity = value;
394 // Depending on whether the avatar is moving or not, change the friction 515 // Depending on whether the avatar is moving or not, change the friction
395 // to keep the avatar from slipping around 516 // to keep the avatar from slipping around
396 if (_velocity.Length() == 0) 517 if (_velocity.Length() == 0)
397 { 518 {
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) 519 if (_currentFriction != BSParam.AvatarStandingFriction)
399 { 520 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 521 _currentFriction = BSParam.AvatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 522 if (PhysBody.HasPhysicalBody)
523 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
402 } 524 }
403 } 525 }
404 else 526 else
405 { 527 {
406 if (_currentFriction != PhysicsScene.Params.avatarFriction) 528 if (_currentFriction != BSParam.AvatarFriction)
407 { 529 {
408 _currentFriction = PhysicsScene.Params.avatarFriction; 530 _currentFriction = BSParam.AvatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 531 if (PhysBody.HasPhysicalBody)
532 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
410 } 533 }
411 } 534 }
412 _velocity = value;
413 // Remember the set velocity so we can suppress the reduction by friction, ...
414 _appliedVelocity = value;
415 535
416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 536 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
417 BulletSimAPI.Activate2(PhysBody.ptr, true); 537 PhysicsScene.PE.Activate(PhysBody, true);
418 } 538 }
419 } 539 }
420 public override OMV.Vector3 Torque { 540 public override OMV.Vector3 Torque {
@@ -439,13 +559,16 @@ public sealed class BSCharacter : BSPhysObject
439 public override OMV.Quaternion Orientation { 559 public override OMV.Quaternion Orientation {
440 get { return _orientation; } 560 get { return _orientation; }
441 set { 561 set {
442 _orientation = value; 562 // Orientation is set zillions of times when an avatar is walking. It's like
443 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 563 // the viewer doesn't trust us.
444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 564 if (_orientation != value)
445 { 565 {
446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 566 _orientation = value;
447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 567 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
448 }); 568 {
569 ForceOrientation = _orientation;
570 });
571 }
449 } 572 }
450 } 573 }
451 // Go directly to Bullet to get/set the value. 574 // Go directly to Bullet to get/set the value.
@@ -453,13 +576,17 @@ public sealed class BSCharacter : BSPhysObject
453 { 576 {
454 get 577 get
455 { 578 {
456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 579 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
457 return _orientation; 580 return _orientation;
458 } 581 }
459 set 582 set
460 { 583 {
461 _orientation = value; 584 _orientation = value;
462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 585 if (PhysBody.HasPhysicalBody)
586 {
587 // _position = PhysicsScene.PE.GetPosition(BSBody);
588 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
589 }
463 } 590 }
464 } 591 }
465 public override int PhysicsActorType { 592 public override int PhysicsActorType {
@@ -482,6 +609,7 @@ public sealed class BSCharacter : BSPhysObject
482 get { return _flying; } 609 get { return _flying; }
483 set { 610 set {
484 _flying = value; 611 _flying = value;
612
485 // simulate flying by changing the effect of gravity 613 // simulate flying by changing the effect of gravity
486 Buoyancy = ComputeBuoyancyFromFlying(_flying); 614 Buoyancy = ComputeBuoyancyFromFlying(_flying);
487 } 615 }
@@ -500,27 +628,18 @@ public sealed class BSCharacter : BSPhysObject
500 get { return _throttleUpdates; } 628 get { return _throttleUpdates; }
501 set { _throttleUpdates = value; } 629 set { _throttleUpdates = value; }
502 } 630 }
503 public override bool IsColliding {
504 get { return (CollidingStep == PhysicsScene.SimulationStep); }
505 set { _isColliding = value; }
506 }
507 public override bool CollidingGround {
508 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
509 set { CollidingGround = value; }
510 }
511 public override bool CollidingObj {
512 get { return _collidingObj; }
513 set { _collidingObj = value; }
514 }
515 public override bool FloatOnWater { 631 public override bool FloatOnWater {
516 set { 632 set {
517 _floatOnWater = value; 633 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 634 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 { 635 {
520 if (_floatOnWater) 636 if (PhysBody.HasPhysicalBody)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 637 {
522 else 638 if (_floatOnWater)
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 639 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
640 else
641 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
642 }
524 }); 643 });
525 } 644 }
526 } 645 }
@@ -549,11 +668,15 @@ public sealed class BSCharacter : BSPhysObject
549 } 668 }
550 public override float ForceBuoyancy { 669 public override float ForceBuoyancy {
551 get { return _buoyancy; } 670 get { return _buoyancy; }
552 set { _buoyancy = value; 671 set {
672 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
673
674 _buoyancy = value;
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 675 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object 676 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 677 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 678 if (PhysBody.HasPhysicalBody)
679 PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav));
557 } 680 }
558 } 681 }
559 682
@@ -589,24 +712,40 @@ public sealed class BSCharacter : BSPhysObject
589 public override float APIDStrength { set { return; } } 712 public override float APIDStrength { set { return; } }
590 public override float APIDDamping { set { return; } } 713 public override float APIDDamping { set { return; } }
591 714
592 public override void AddForce(OMV.Vector3 force, bool pushforce) { 715 public override void AddForce(OMV.Vector3 force, bool pushforce)
716 {
717 // Since this force is being applied in only one step, make this a force per second.
718 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
719 AddForce(addForce, pushforce, false);
720 }
721 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
593 if (force.IsFinite()) 722 if (force.IsFinite())
594 { 723 {
595 _force.X += force.X; 724 float magnitude = force.Length();
596 _force.Y += force.Y; 725 if (magnitude > BSParam.MaxAddForceMagnitude)
597 _force.Z += force.Z;
598 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
600 { 726 {
601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 727 // Force has a limit
602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 728 force = force / magnitude * BSParam.MaxAddForceMagnitude;
729 }
730
731 OMV.Vector3 addForce = force;
732 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
733
734 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
735 {
736 // Bullet adds this central force to the total force for this tick
737 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
738 if (PhysBody.HasPhysicalBody)
739 {
740 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
741 }
603 }); 742 });
604 } 743 }
605 else 744 else
606 { 745 {
607 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); 746 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
747 return;
608 } 748 }
609 //m_lastUpdateSent = false;
610 } 749 }
611 750
612 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 751 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@@ -614,24 +753,31 @@ public sealed class BSCharacter : BSPhysObject
614 public override void SetMomentum(OMV.Vector3 momentum) { 753 public override void SetMomentum(OMV.Vector3 momentum) {
615 } 754 }
616 755
617 private void ComputeAvatarScale(OMV.Vector3 size) 756 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
618 { 757 {
619 // The 'size' given by the simulator is the mid-point of the avatar 758 OMV.Vector3 newScale;
620 // and X and Y are unspecified. 759
621 760 // Bullet's capsule total height is the "passed height + radius * 2";
622 OMV.Vector3 newScale = size; 761 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 762 // The number we pass in for 'scaling' is the multiplier to get that base
624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 763 // shape to be the size desired.
625 764 // So, when creating the scale for the avatar height, we take the passed height
626 // From the total height, remove the capsule half spheres that are at each end 765 // (size.Z) and remove the caps.
627 // The 1.15f came from ODE. Not sure what this factors in. 766 // Another oddity of the Bullet capsule implementation is that it presumes the Y
628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); 767 // dimension is the radius of the capsule. Even though some of the code allows
768 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
769
770 // Scale is multiplier of radius with one of "0.5"
771 newScale.X = size.X / 2f;
772 newScale.Y = size.Y / 2f;
629 773
630 // The total scale height is the central cylindar plus the caps on the two ends. 774 // The total scale height is the central cylindar plus the caps on the two ends.
631 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); 775 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
776 // If smaller than the endcaps, just fake like we're almost that small
777 if (newScale.Z < 0)
778 newScale.Z = 0.1f;
632 779
633 // Convert diameters to radii and height to half height -- the way Bullet expects it. 780 return newScale;
634 Scale = newScale / 2f;
635 } 781 }
636 782
637 // set _avatarVolume and _mass based on capsule size, _density and Scale 783 // set _avatarVolume and _mass based on capsule size, _density and Scale
@@ -639,14 +785,14 @@ public sealed class BSCharacter : BSPhysObject
639 { 785 {
640 _avatarVolume = (float)( 786 _avatarVolume = (float)(
641 Math.PI 787 Math.PI
642 * Scale.X 788 * Size.X / 2f
643 * Scale.Y // the area of capsule cylinder 789 * Size.Y / 2f // the area of capsule cylinder
644 * Scale.Z // times height of capsule cylinder 790 * Size.Z // times height of capsule cylinder
645 + 1.33333333f 791 + 1.33333333f
646 * Math.PI 792 * Math.PI
647 * Scale.X 793 * Size.X / 2f
648 * Math.Min(Scale.X, Scale.Y) 794 * Math.Min(Size.X, Size.Y) / 2
649 * Scale.Y // plus the volume of the capsule end caps 795 * Size.Y / 2f // plus the volume of the capsule end caps
650 ); 796 );
651 _mass = _avatarDensity * _avatarVolume; 797 _mass = _avatarDensity * _avatarVolume;
652 } 798 }
@@ -660,6 +806,7 @@ public sealed class BSCharacter : BSPhysObject
660 _velocity = entprop.Velocity; 806 _velocity = entprop.Velocity;
661 _acceleration = entprop.Acceleration; 807 _acceleration = entprop.Acceleration;
662 _rotationalVelocity = entprop.RotationalVelocity; 808 _rotationalVelocity = entprop.RotationalVelocity;
809
663 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 810 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
664 PositionSanityCheck(true); 811 PositionSanityCheck(true);
665 812
@@ -667,17 +814,8 @@ public sealed class BSCharacter : BSPhysObject
667 LastEntityProperties = CurrentEntityProperties; 814 LastEntityProperties = CurrentEntityProperties;
668 CurrentEntityProperties = entprop; 815 CurrentEntityProperties = entprop;
669 816
670 if (entprop.Velocity != LastEntityProperties.Velocity)
671 {
672 // Changes in the velocity are suppressed in avatars.
673 // That's just the way they are defined.
674 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
675 _velocity = avVel;
676 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
677 }
678
679 // Tell the linkset about value changes 817 // Tell the linkset about value changes
680 Linkset.UpdateProperties(this); 818 Linkset.UpdateProperties(this, true);
681 819
682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 820 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
683 // base.RequestPhysicsterseUpdate(); 821 // base.RequestPhysicsterseUpdate();