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