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.cs717
1 files changed, 426 insertions, 291 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index e2f7af9..4c195e1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -28,62 +28,48 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection; 29using System.Reflection;
30using log4net; 30using log4net;
31using OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSCharacter : PhysicsActor 37public sealed class BSCharacter : BSPhysObject
38{ 38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]"; 40 private static readonly string LogHeader = "[BULLETS CHAR]";
41 41
42 private BSScene _scene;
43 public BSScene Scene { get { return _scene; } }
44 private String _avName;
45 // private bool _stopped; 42 // private bool _stopped;
46 private Vector3 _size; 43 private OMV.Vector3 _size;
47 private Vector3 _scale;
48 private PrimitiveBaseShape _pbs;
49 private uint _localID = 0;
50 private bool _grabbed; 44 private bool _grabbed;
51 private bool _selected; 45 private bool _selected;
52 private Vector3 _position; 46 private OMV.Vector3 _position;
53 private float _mass; 47 private float _mass;
54 public float _density; 48 private float _avatarDensity;
55 public float _avatarVolume; 49 private float _avatarVolume;
56 private Vector3 _force; 50 private OMV.Vector3 _force;
57 private Vector3 _velocity; 51 private OMV.Vector3 _velocity;
58 private Vector3 _torque; 52 private OMV.Vector3 _torque;
59 private float _collisionScore; 53 private float _collisionScore;
60 private Vector3 _acceleration; 54 private OMV.Vector3 _acceleration;
61 private Quaternion _orientation; 55 private OMV.Quaternion _orientation;
62 private int _physicsActorType; 56 private int _physicsActorType;
63 private bool _isPhysical; 57 private bool _isPhysical;
64 private bool _flying; 58 private bool _flying;
65 private bool _setAlwaysRun; 59 private bool _setAlwaysRun;
66 private bool _throttleUpdates; 60 private bool _throttleUpdates;
67 private bool _isColliding; 61 private bool _isColliding;
68 private long _collidingStep;
69 private bool _collidingGround;
70 private long _collidingGroundStep;
71 private bool _collidingObj; 62 private bool _collidingObj;
72 private bool _floatOnWater; 63 private bool _floatOnWater;
73 private Vector3 _rotationalVelocity; 64 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic; 65 private bool _kinematic;
75 private float _buoyancy; 66 private float _buoyancy;
76 67
77 private BulletBody m_body; 68 // The friction and velocity of the avatar is modified depending on whether walking or not.
78 public BulletBody Body { 69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
79 get { return m_body; } 70 private float _currentFriction; // the friction currently being used (changed by setVelocity).
80 set { m_body = value; }
81 }
82
83 private int _subscribedEventsMs = 0;
84 private int _nextCollisionOkTime = 0;
85 71
86 private Vector3 _PIDTarget; 72 private OMV.Vector3 _PIDTarget;
87 private bool _usePID; 73 private bool _usePID;
88 private float _PIDTau; 74 private float _PIDTau;
89 private bool _useHoverPID; 75 private bool _useHoverPID;
@@ -91,332 +77,529 @@ public class BSCharacter : PhysicsActor
91 private PIDHoverType _PIDHoverType; 77 private PIDHoverType _PIDHoverType;
92 private float _PIDHoverTao; 78 private float _PIDHoverTao;
93 79
94 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) 80 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
81 : base(parent_scene, localID, avName, "BSCharacter")
95 { 82 {
96 _localID = localID; 83 _physicsActorType = (int)ActorTypes.Agent;
97 _avName = avName;
98 _scene = parent_scene;
99 _position = pos; 84 _position = pos;
85
86 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
87 // replace with the default values.
100 _size = size; 88 _size = size;
89 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
90 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
91
101 _flying = isFlying; 92 _flying = isFlying;
102 _orientation = Quaternion.Identity; 93 _orientation = OMV.Quaternion.Identity;
103 _velocity = Vector3.Zero; 94 _velocity = OMV.Vector3.Zero;
95 _appliedVelocity = OMV.Vector3.Zero;
104 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 96 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
97 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
98 _avatarDensity = PhysicsScene.Params.avatarDensity;
99
105 // The dimensions of the avatar capsule are kept in the scale. 100 // The dimensions of the avatar capsule are kept in the scale.
106 // 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.
107 _scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z); 102 ComputeAvatarScale(_size);
108 _density = _scene.Params.avatarDensity; 103 // set _avatarVolume and _mass based on capsule size, _density and Scale
109 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale 104 ComputeAvatarVolumeAndMass();
110 105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
111 ShapeData shapeData = new ShapeData(); 106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
112 shapeData.ID = _localID;
113 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
114 shapeData.Position = _position;
115 shapeData.Rotation = _orientation;
116 shapeData.Velocity = _velocity;
117 shapeData.Scale = _scale;
118 shapeData.Mass = _mass;
119 shapeData.Buoyancy = _buoyancy;
120 shapeData.Static = ShapeData.numericFalse;
121 shapeData.Friction = _scene.Params.avatarFriction;
122 shapeData.Restitution = _scene.Params.avatarRestitution;
123 107
124 // do actual create at taint time 108 // do actual create at taint time
125 _scene.TaintedObject("BSCharacter.create", delegate() 109 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
126 { 110 {
127 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); 111 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null);
128 114
129 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); 115 SetPhysicalProperties();
130 // avatars get all collisions no matter what
131 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
132 }); 116 });
133
134 return; 117 return;
135 } 118 }
136 119
137 // called when this character is being destroyed and the resources should be released 120 // called when this character is being destroyed and the resources should be released
138 public void Destroy() 121 public override void Destroy()
139 { 122 {
140 // DetailLog("{0},BSCharacter.Destroy", LocalID); 123 DetailLog("{0},BSCharacter.Destroy", LocalID);
141 _scene.TaintedObject("BSCharacter.destroy", delegate() 124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
142 { 125 {
143 BulletSimAPI.DestroyObject(_scene.WorldID, _localID); 126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
144 }); 128 });
145 } 129 }
146 130
131 private void SetPhysicalProperties()
132 {
133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
134
135 ZeroMotion(true);
136 ForcePosition = _position;
137 // Set the velocity and compute the proper friction
138 ForceVelocity = _velocity;
139
140 // 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.
142 Flying = _flying;
143
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
148 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
149 {
150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
152 }
153
154 UpdatePhysicalMassProperties(RawMass);
155
156 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero);
158
159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
160
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
162
163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
166
167 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr,
169 (uint)CollisionFilterGroups.AvatarFilter,
170 (uint)CollisionFilterGroups.AvatarMask);
171 }
172
147 public override void RequestPhysicsterseUpdate() 173 public override void RequestPhysicsterseUpdate()
148 { 174 {
149 base.RequestPhysicsterseUpdate(); 175 base.RequestPhysicsterseUpdate();
150 } 176 }
151 // No one calls this method so I don't know what it could possibly mean 177 // No one calls this method so I don't know what it could possibly mean
152 public override bool Stopped { 178 public override bool Stopped { get { return false; } }
153 get { return false; } 179
154 } 180 public override OMV.Vector3 Size {
155 public override Vector3 Size {
156 get 181 get
157 { 182 {
158 // Avatar capsule size is kept in the scale parameter. 183 // Avatar capsule size is kept in the scale parameter.
159 return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); 184 return _size;
160 } 185 }
161 186
162 set { 187 set {
163 // When an avatar's size is set, only the height is changed 188 // When an avatar's size is set, only the height is changed.
164 // and that really only depends on the radius.
165 _size = value; 189 _size = value;
166 _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); 190 ComputeAvatarScale(_size);
167
168 // TODO: something has to be done with the avatar's vertical position
169
170 ComputeAvatarVolumeAndMass(); 191 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
171 194
172 _scene.TaintedObject("BSCharacter.setSize", delegate() 195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
173 { 196 {
174 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true); 197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
198 UpdatePhysicalMassProperties(RawMass);
175 }); 199 });
176 200
177 } 201 }
178 } 202 }
179 public override PrimitiveBaseShape Shape { 203
180 set { _pbs = value; 204 public override OMV.Vector3 Scale { get; set; }
181 } 205
206 public override PrimitiveBaseShape Shape
207 {
208 set { BaseShape = value; }
182 } 209 }
183 public override uint LocalID { 210 // I want the physics engine to make an avatar capsule
184 set { _localID = value; 211 public override BSPhysicsShapeType PreferredPhysicalShape
185 } 212 {
186 get { return _localID; } 213 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
187 } 214 }
188 public override bool Grabbed { 215
189 set { _grabbed = value; 216 public override bool Grabbed {
190 } 217 set { _grabbed = value; }
191 } 218 }
192 public override bool Selected { 219 public override bool Selected {
193 set { _selected = value; 220 set { _selected = value; }
194 }
195 } 221 }
196 public override void CrossingFailure() { return; } 222 public override void CrossingFailure() { return; }
197 public override void link(PhysicsActor obj) { return; } 223 public override void link(PhysicsActor obj) { return; }
198 public override void delink() { return; } 224 public override void delink() { return; }
199 public override void LockAngularMotion(Vector3 axis) { return; }
200 225
201 public override Vector3 Position { 226 // Set motion values to zero.
227 // Do it to the properties so the values get set in the physics engine.
228 // Push the setting of the values to the viewer.
229 // Called at taint time!
230 public override void ZeroMotion(bool inTaintTime)
231 {
232 _velocity = OMV.Vector3.Zero;
233 _acceleration = OMV.Vector3.Zero;
234 _rotationalVelocity = OMV.Vector3.Zero;
235
236 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
240 });
241 }
242 public override void ZeroAngularMotion(bool inTaintTime)
243 {
244 _rotationalVelocity = OMV.Vector3.Zero;
245
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
250 // The next also get rid of applied linear force but the linear velocity is untouched.
251 BulletSimAPI.ClearForces2(PhysBody.ptr);
252 });
253 }
254
255
256 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
257
258 public override OMV.Vector3 RawPosition
259 {
260 get { return _position; }
261 set { _position = value; }
262 }
263 public override OMV.Vector3 Position {
202 get { 264 get {
203 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 265 // Don't refetch the position because this function is called a zillion times
204 return _position; 266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
205 } 267 return _position;
268 }
206 set { 269 set {
207 _position = value; 270 _position = value;
208 PositionSanityCheck(); 271 PositionSanityCheck();
209 272
210 _scene.TaintedObject("BSCharacter.setPosition", delegate() 273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
211 { 274 {
212 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
213 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
214 }); 277 });
215 } 278 }
279 }
280 public override OMV.Vector3 ForcePosition {
281 get {
282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
283 return _position;
284 }
285 set {
286 _position = value;
287 PositionSanityCheck();
288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
289 }
216 } 290 }
217 291
292
218 // Check that the current position is sane and, if not, modify the position to make it so. 293 // Check that the current position is sane and, if not, modify the position to make it so.
219 // Check for being below terrain and being out of bounds. 294 // Check for being below terrain or on water.
220 // Returns 'true' of the position was made sane by some action. 295 // Returns 'true' of the position was made sane by some action.
221 private bool PositionSanityCheck() 296 private bool PositionSanityCheck()
222 { 297 {
223 bool ret = false; 298 bool ret = false;
224 299
225 // If below the ground, move the avatar up 300 // If below the ground, move the avatar up
226 float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); 301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
227 if (_position.Z < terrainHeight) 302 if (Position.Z < terrainHeight)
228 { 303 {
229 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); 304 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
230 _position.Z = terrainHeight + 2.0f; 305 _position.Z = terrainHeight + 2.0f;
231 ret = true; 306 ret = true;
232 } 307 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight)
312 {
313 _position.Z = waterHeight;
314 ret = true;
315 }
316 }
233 317
234 // TODO: check for out of bounds 318 // TODO: check for out of bounds
319 return ret;
320 }
235 321
322 // A version of the sanity check that also makes sure a new position value is
323 // pushed back to the physics engine. This routine would be used by anyone
324 // who is not already pushing the value.
325 private bool PositionSanityCheck(bool inTaintTime)
326 {
327 bool ret = false;
328 if (PositionSanityCheck())
329 {
330 // The new position value must be pushed into the physics engine but we can't
331 // just assign to "Position" because of potential call loops.
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
336 });
337 ret = true;
338 }
236 return ret; 339 return ret;
237 } 340 }
238 341
239 public override float Mass { 342 public override float Mass { get { return _mass; } }
240 get { 343
241 return _mass; 344 // used when we only want this prim's mass and not the linkset thing
242 } 345 public override float RawMass {
346 get {return _mass; }
243 } 347 }
244 public override Vector3 Force { 348 public override void UpdatePhysicalMassProperties(float physMass)
245 get { return _force; } 349 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
352 }
353
354 public override OMV.Vector3 Force {
355 get { return _force; }
246 set { 356 set {
247 _force = value; 357 _force = value;
248 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 358 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
249 Scene.TaintedObject("BSCharacter.SetForce", delegate() 359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
250 { 360 {
251 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
252 BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force); 362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
253 }); 363 });
254 } 364 }
255 } 365 }
256 366
257 public override int VehicleType { 367 // Avatars don't do vehicles
258 get { return 0; } 368 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
259 set { return; }
260 }
261 public override void VehicleFloatParam(int param, float value) { } 369 public override void VehicleFloatParam(int param, float value) { }
262 public override void VehicleVectorParam(int param, Vector3 value) {} 370 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
263 public override void VehicleRotationParam(int param, Quaternion rotation) { } 371 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
264 public override void VehicleFlags(int param, bool remove) { } 372 public override void VehicleFlags(int param, bool remove) { }
265 373
266 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 374 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
267 public override void SetVolumeDetect(int param) { return; } 375 public override void SetVolumeDetect(int param) { return; }
268 376
269 public override Vector3 GeometricCenter { get { return Vector3.Zero; } } 377 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
270 public override Vector3 CenterOfMass { get { return Vector3.Zero; } } 378 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
271 public override Vector3 Velocity { 379 public override OMV.Vector3 Velocity {
272 get { return _velocity; } 380 get { return _velocity; }
273 set { 381 set {
274 _velocity = value; 382 _velocity = value;
275 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 383 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
276 _scene.TaintedObject("BSCharacter.setVelocity", delegate() 384 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
277 { 385 {
278 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 386 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
279 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); 387 ForceVelocity = _velocity;
280 }); 388 });
281 } 389 }
282 } 390 }
283 public override Vector3 Torque { 391 public override OMV.Vector3 ForceVelocity {
284 get { return _torque; } 392 get { return _velocity; }
285 set { _torque = value; 393 set {
286 } 394 // Depending on whether the avatar is moving or not, change the friction
395 // to keep the avatar from slipping around
396 if (_velocity.Length() == 0)
397 {
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
399 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
402 }
403 }
404 else
405 {
406 if (_currentFriction != PhysicsScene.Params.avatarFriction)
407 {
408 _currentFriction = PhysicsScene.Params.avatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
410 }
411 }
412 _velocity = value;
413 // Remember the set velocity so we can suppress the reduction by friction, ...
414 _appliedVelocity = value;
415
416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
417 BulletSimAPI.Activate2(PhysBody.ptr, true);
418 }
287 } 419 }
288 public override float CollisionScore { 420 public override OMV.Vector3 Torque {
289 get { return _collisionScore; } 421 get { return _torque; }
290 set { _collisionScore = value; 422 set { _torque = value;
291 } 423 }
424 }
425 public override float CollisionScore {
426 get { return _collisionScore; }
427 set { _collisionScore = value;
428 }
292 } 429 }
293 public override Vector3 Acceleration { 430 public override OMV.Vector3 Acceleration {
294 get { return _acceleration; } 431 get { return _acceleration; }
295 set { _acceleration = value; } 432 set { _acceleration = value; }
296 } 433 }
297 public override Quaternion Orientation { 434 public override OMV.Quaternion RawOrientation
298 get { return _orientation; } 435 {
436 get { return _orientation; }
437 set { _orientation = value; }
438 }
439 public override OMV.Quaternion Orientation {
440 get { return _orientation; }
299 set { 441 set {
300 _orientation = value; 442 _orientation = value;
301 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 443 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
302 _scene.TaintedObject("BSCharacter.setOrientation", delegate() 444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
303 { 445 {
304 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
305 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
306 }); 448 });
307 } 449 }
308 } 450 }
309 public override int PhysicsActorType { 451 // Go directly to Bullet to get/set the value.
310 get { return _physicsActorType; } 452 public override OMV.Quaternion ForceOrientation
311 set { _physicsActorType = value; 453 {
312 } 454 get
455 {
456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
457 return _orientation;
458 }
459 set
460 {
461 _orientation = value;
462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
463 }
313 } 464 }
314 public override bool IsPhysical { 465 public override int PhysicsActorType {
315 get { return _isPhysical; } 466 get { return _physicsActorType; }
467 set { _physicsActorType = value;
468 }
469 }
470 public override bool IsPhysical {
471 get { return _isPhysical; }
316 set { _isPhysical = value; 472 set { _isPhysical = value;
317 } 473 }
474 }
475 public override bool IsSolid {
476 get { return true; }
318 } 477 }
319 public override bool Flying { 478 public override bool IsStatic {
320 get { return _flying; } 479 get { return false; }
480 }
481 public override bool Flying {
482 get { return _flying; }
321 set { 483 set {
322 if (_flying != value) 484 _flying = value;
323 { 485 // simulate flying by changing the effect of gravity
324 _flying = value; 486 Buoyancy = ComputeBuoyancyFromFlying(_flying);
325 // simulate flying by changing the effect of gravity 487 }
326 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
327 }
328 }
329 } 488 }
489 // Flying is implimented by changing the avatar's buoyancy.
490 // Would this be done better with a vehicle type?
330 private float ComputeBuoyancyFromFlying(bool ifFlying) { 491 private float ComputeBuoyancyFromFlying(bool ifFlying) {
331 return ifFlying ? 1f : 0f; 492 return ifFlying ? 1f : 0f;
332 } 493 }
333 public override bool 494 public override bool
334 SetAlwaysRun { 495 SetAlwaysRun {
335 get { return _setAlwaysRun; } 496 get { return _setAlwaysRun; }
336 set { _setAlwaysRun = value; } 497 set { _setAlwaysRun = value; }
337 } 498 }
338 public override bool ThrottleUpdates { 499 public override bool ThrottleUpdates {
339 get { return _throttleUpdates; } 500 get { return _throttleUpdates; }
340 set { _throttleUpdates = value; } 501 set { _throttleUpdates = value; }
341 } 502 }
342 public override bool IsColliding { 503 public override bool IsColliding {
343 get { return (_collidingStep == _scene.SimulationStep); } 504 get { return (CollidingStep == PhysicsScene.SimulationStep); }
344 set { _isColliding = value; } 505 set { _isColliding = value; }
345 } 506 }
346 public override bool CollidingGround { 507 public override bool CollidingGround {
347 get { return (_collidingGroundStep == _scene.SimulationStep); } 508 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
348 set { _collidingGround = value; } 509 set { CollidingGround = value; }
349 } 510 }
350 public override bool CollidingObj { 511 public override bool CollidingObj {
351 get { return _collidingObj; } 512 get { return _collidingObj; }
352 set { _collidingObj = value; } 513 set { _collidingObj = value; }
353 } 514 }
354 public override bool FloatOnWater { 515 public override bool FloatOnWater {
355 set { _floatOnWater = value; } 516 set {
517 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 {
520 if (_floatOnWater)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
522 else
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
524 });
525 }
526 }
527 public override OMV.Vector3 RotationalVelocity {
528 get { return _rotationalVelocity; }
529 set { _rotationalVelocity = value; }
356 } 530 }
357 public override Vector3 RotationalVelocity { 531 public override OMV.Vector3 ForceRotationalVelocity {
358 get { return _rotationalVelocity; } 532 get { return _rotationalVelocity; }
359 set { _rotationalVelocity = value; } 533 set { _rotationalVelocity = value; }
360 } 534 }
361 public override bool Kinematic { 535 public override bool Kinematic {
362 get { return _kinematic; } 536 get { return _kinematic; }
363 set { _kinematic = value; } 537 set { _kinematic = value; }
364 } 538 }
365 // neg=fall quickly, 0=1g, 1=0g, pos=float up 539 // neg=fall quickly, 0=1g, 1=0g, pos=float up
366 public override float Buoyancy { 540 public override float Buoyancy {
367 get { return _buoyancy; } 541 get { return _buoyancy; }
368 set { _buoyancy = value; 542 set { _buoyancy = value;
369 _scene.TaintedObject("BSCharacter.setBuoyancy", delegate() 543 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
370 { 544 {
371 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 545 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
372 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); 546 ForceBuoyancy = _buoyancy;
373 }); 547 });
374 } 548 }
549 }
550 public override float ForceBuoyancy {
551 get { return _buoyancy; }
552 set { _buoyancy = value;
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
557 }
375 } 558 }
376 559
377 // Used for MoveTo 560 // Used for MoveTo
378 public override Vector3 PIDTarget { 561 public override OMV.Vector3 PIDTarget {
379 set { _PIDTarget = value; } 562 set { _PIDTarget = value; }
380 } 563 }
381 public override bool PIDActive { 564 public override bool PIDActive {
382 set { _usePID = value; } 565 set { _usePID = value; }
383 } 566 }
384 public override float PIDTau { 567 public override float PIDTau {
385 set { _PIDTau = value; } 568 set { _PIDTau = value; }
386 } 569 }
387 570
388 // Used for llSetHoverHeight and maybe vehicle height 571 // Used for llSetHoverHeight and maybe vehicle height
389 // Hover Height will override MoveTo target's Z 572 // Hover Height will override MoveTo target's Z
390 public override bool PIDHoverActive { 573 public override bool PIDHoverActive {
391 set { _useHoverPID = value; } 574 set { _useHoverPID = value; }
392 } 575 }
393 public override float PIDHoverHeight { 576 public override float PIDHoverHeight {
394 set { _PIDHoverHeight = value; } 577 set { _PIDHoverHeight = value; }
395 } 578 }
396 public override PIDHoverType PIDHoverType { 579 public override PIDHoverType PIDHoverType {
397 set { _PIDHoverType = value; } 580 set { _PIDHoverType = value; }
398 } 581 }
399 public override float PIDHoverTau { 582 public override float PIDHoverTau {
400 set { _PIDHoverTao = value; } 583 set { _PIDHoverTao = value; }
401 } 584 }
402 585
403 // For RotLookAt 586 // For RotLookAt
404 public override Quaternion APIDTarget { set { return; } } 587 public override OMV.Quaternion APIDTarget { set { return; } }
405 public override bool APIDActive { set { return; } } 588 public override bool APIDActive { set { return; } }
406 public override float APIDStrength { set { return; } } 589 public override float APIDStrength { set { return; } }
407 public override float APIDDamping { set { return; } } 590 public override float APIDDamping { set { return; } }
408 591
409 public override void AddForce(Vector3 force, bool pushforce) { 592 public override void AddForce(OMV.Vector3 force, bool pushforce) {
410 if (force.IsFinite()) 593 if (force.IsFinite())
411 { 594 {
412 _force.X += force.X; 595 _force.X += force.X;
413 _force.Y += force.Y; 596 _force.Y += force.Y;
414 _force.Z += force.Z; 597 _force.Z += force.Z;
415 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); 598 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
416 _scene.TaintedObject("BSCharacter.AddForce", delegate() 599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
417 { 600 {
418 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
419 BulletSimAPI.AddObjectForce2(Body.Ptr, _force); 602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
420 }); 603 });
421 } 604 }
422 else 605 else
@@ -426,129 +609,81 @@ public class BSCharacter : PhysicsActor
426 //m_lastUpdateSent = false; 609 //m_lastUpdateSent = false;
427 } 610 }
428 611
429 public override void AddAngularForce(Vector3 force, bool pushforce) { 612 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
430 } 613 }
431 public override void SetMomentum(Vector3 momentum) { 614 public override void SetMomentum(OMV.Vector3 momentum) {
432 } 615 }
433 616
434 // Turn on collision events at a rate no faster than one every the given milliseconds 617 private void ComputeAvatarScale(OMV.Vector3 size)
435 public override void SubscribeEvents(int ms) { 618 {
436 _subscribedEventsMs = ms; 619 // The 'size' given by the simulator is the mid-point of the avatar
437 if (ms > 0) 620 // and X and Y are unspecified.
438 {
439 // make sure first collision happens
440 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
441 621
442 Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate() 622 OMV.Vector3 newScale = size;
443 { 623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
444 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
445 }); 625
446 } 626 // From the total height, remove the capsule half spheres that are at each end
447 } 627 // The 1.15f came from ODE. Not sure what this factors in.
448 // Stop collision events 628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
449 public override void UnSubscribeEvents() { 629
450 _subscribedEventsMs = 0; 630 // The total scale height is the central cylindar plus the caps on the two ends.
451 // Avatars get all their collision events 631 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
452 // Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate() 632
453 // { 633 // Convert diameters to radii and height to half height -- the way Bullet expects it.
454 // BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 634 Scale = newScale / 2f;
455 // });
456 }
457 // Return 'true' if someone has subscribed to events
458 public override bool SubscribedEvents() {
459 return (_subscribedEventsMs > 0);
460 } 635 }
461 636
462 // set _avatarVolume and _mass based on capsule size, _density and _scale 637 // set _avatarVolume and _mass based on capsule size, _density and Scale
463 private void ComputeAvatarVolumeAndMass() 638 private void ComputeAvatarVolumeAndMass()
464 { 639 {
465 _avatarVolume = (float)( 640 _avatarVolume = (float)(
466 Math.PI 641 Math.PI
467 * _scale.X 642 * Scale.X
468 * _scale.Y // the area of capsule cylinder 643 * Scale.Y // the area of capsule cylinder
469 * _scale.Z // times height of capsule cylinder 644 * Scale.Z // times height of capsule cylinder
470 + 1.33333333f 645 + 1.33333333f
471 * Math.PI 646 * Math.PI
472 * _scale.X 647 * Scale.X
473 * Math.Min(_scale.X, _scale.Y) 648 * Math.Min(Scale.X, Scale.Y)
474 * _scale.Y // plus the volume of the capsule end caps 649 * Scale.Y // plus the volume of the capsule end caps
475 ); 650 );
476 _mass = _density * _avatarVolume; 651 _mass = _avatarDensity * _avatarVolume;
477 } 652 }
478 653
479 // The physics engine says that properties have updated. Update same and inform 654 // The physics engine says that properties have updated. Update same and inform
480 // the world that things have changed. 655 // the world that things have changed.
481 public void UpdateProperties(EntityProperties entprop) 656 public override void UpdateProperties(EntityProperties entprop)
482 { 657 {
483 _position = entprop.Position; 658 _position = entprop.Position;
484 _orientation = entprop.Rotation; 659 _orientation = entprop.Rotation;
485 _velocity = entprop.Velocity; 660 _velocity = entprop.Velocity;
486 _acceleration = entprop.Acceleration; 661 _acceleration = entprop.Acceleration;
487 _rotationalVelocity = entprop.RotationalVelocity; 662 _rotationalVelocity = entprop.RotationalVelocity;
488 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 663 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
489 // base.RequestPhysicsterseUpdate(); 664 PositionSanityCheck(true);
490 665
491 /* 666 // remember the current and last set values
492 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 667 LastEntityProperties = CurrentEntityProperties;
493 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 668 CurrentEntityProperties = entprop;
494 entprop.Acceleration, entprop.RotationalVelocity);
495 */
496 }
497 669
498 // Called by the scene when a collision with this object is reported 670 if (entprop.Velocity != LastEntityProperties.Velocity)
499 // The collision, if it should be reported to the character, is placed in a collection
500 // that will later be sent to the simulator when SendCollisions() is called.
501 CollisionEventUpdate collisionCollection = null;
502 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
503 {
504 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
505
506 // The following makes IsColliding() and IsCollidingGround() work
507 _collidingStep = _scene.SimulationStep;
508 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
509 { 671 {
510 _collidingGroundStep = _scene.SimulationStep; 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);
511 } 677 }
512 // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
513 678
514 // throttle collisions to the rate specified in the subscription 679 // Tell the linkset about value changes
515 if (_subscribedEventsMs != 0) { 680 Linkset.UpdateProperties(this);
516 int nowTime = _scene.SimulationNowTime;
517 if (nowTime >= _nextCollisionOkTime) {
518 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
519 681
520 if (collisionCollection == null) 682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
521 collisionCollection = new CollisionEventUpdate(); 683 // base.RequestPhysicsterseUpdate();
522 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
523 }
524 }
525 }
526 684
527 public void SendCollisions() 685 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
528 { 686 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
529 /*
530 if (collisionCollection != null && collisionCollection.Count > 0)
531 {
532 base.SendCollisionUpdate(collisionCollection);
533 collisionCollection = null;
534 }
535 */
536 // Kludge to make a collision call even if there are no collisions.
537 // This causes the avatar animation to get updated.
538 if (collisionCollection == null)
539 collisionCollection = new CollisionEventUpdate();
540 base.SendCollisionUpdate(collisionCollection);
541 // If there were any collisions in the collection, make sure we don't use the
542 // same instance next time.
543 if (collisionCollection.Count > 0)
544 collisionCollection = null;
545 // End kludge
546 }
547
548 // Invoke the detailed logger and output something if it's enabled.
549 private void DetailLog(string msg, params Object[] args)
550 {
551 Scene.PhysicsLogging.Write(msg, args);
552 } 687 }
553} 688}
554} 689}