aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs814
1 files changed, 814 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
new file mode 100644
index 0000000..4c4e950
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
@@ -0,0 +1,814 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using log4net;
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37public sealed class BSCharacter : BSPhysObject
38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]";
41
42 // private bool _stopped;
43 private OMV.Vector3 _size;
44 private bool _grabbed;
45 private bool _selected;
46 private OMV.Vector3 _position;
47 private float _mass;
48 private float _avatarDensity;
49 private float _avatarVolume;
50 private OMV.Vector3 _force;
51 private OMV.Vector3 _velocity;
52 private OMV.Vector3 _torque;
53 private float _collisionScore;
54 private OMV.Vector3 _acceleration;
55 private OMV.Quaternion _orientation;
56 private int _physicsActorType;
57 private bool _isPhysical;
58 private bool _flying;
59 private bool _setAlwaysRun;
60 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic;
66 private float _buoyancy;
67
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).
71
72 private BSVMotor _velocityMotor;
73
74 private OMV.Vector3 _PIDTarget;
75 private bool _usePID;
76 private float _PIDTau;
77 private bool _useHoverPID;
78 private float _PIDHoverHeight;
79 private PIDHoverType _PIDHoverType;
80 private float _PIDHoverTao;
81
82 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
83 : base(parent_scene, localID, avName, "BSCharacter")
84 {
85 _physicsActorType = (int)ActorTypes.Agent;
86 _position = pos;
87
88 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
89 // replace with the default values.
90 _size = size;
91 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
92 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
93
94 // A motor to control the acceleration and deceleration of the avatar movement.
95 // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
96 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
97 // Infinite decay and timescale values so motor only changes current to target values.
98 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
99 0.2f, // time scale
100 BSMotor.Infinite, // decay time scale
101 BSMotor.InfiniteVector, // friction timescale
102 1f // efficiency
103 );
104 _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
105
106 _flying = isFlying;
107 _orientation = OMV.Quaternion.Identity;
108 _velocity = OMV.Vector3.Zero;
109 _appliedVelocity = OMV.Vector3.Zero;
110 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
111 _currentFriction = BSParam.AvatarStandingFriction;
112 _avatarDensity = BSParam.AvatarDensity;
113
114 // The dimensions of the avatar capsule are kept in the scale.
115 // Physics creates a unit capsule which is scaled by the physics engine.
116 ComputeAvatarScale(_size);
117 // set _avatarVolume and _mass based on capsule size, _density and Scale
118 ComputeAvatarVolumeAndMass();
119 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
120 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
121
122 // do actual creation in taint time
123 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
124 {
125 DetailLog("{0},BSCharacter.create,taint", LocalID);
126 // New body and shape into PhysBody and PhysShape
127 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
128
129 SetPhysicalProperties();
130 });
131 return;
132 }
133
134 // called when this character is being destroyed and the resources should be released
135 public override void Destroy()
136 {
137 base.Destroy();
138
139 DetailLog("{0},BSCharacter.Destroy", LocalID);
140 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
141 {
142 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
143 PhysBody.Clear();
144 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
145 PhysShape.Clear();
146 });
147 }
148
149 private void SetPhysicalProperties()
150 {
151 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
152
153 ZeroMotion(true);
154 ForcePosition = _position;
155 // Set the velocity and compute the proper friction
156 ForceVelocity = _velocity;
157 // Setting the current and target in the motor will cause it to start computing any deceleration.
158 _velocityMotor.Reset();
159 _velocityMotor.SetCurrent(_velocity);
160 _velocityMotor.SetTarget(_velocity);
161 _velocityMotor.Enabled = false;
162
163 // This will enable or disable the flying buoyancy of the avatar.
164 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
165 Flying = _flying;
166
167 BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution);
168 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
169 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
170 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
171 if (BSParam.CcdMotionThreshold > 0f)
172 {
173 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
174 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
175 }
176
177 UpdatePhysicalMassProperties(RawMass);
178
179 // Make so capsule does not fall over
180 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero);
181
182 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
183
184 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation);
185
186 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
187 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
188 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
189
190 // Do this after the object has been added to the world
191 PhysBody.collisionType = CollisionType.Avatar;
192 PhysBody.ApplyCollisionMask();
193 }
194
195 public override void RequestPhysicsterseUpdate()
196 {
197 base.RequestPhysicsterseUpdate();
198 }
199 // No one calls this method so I don't know what it could possibly mean
200 public override bool Stopped { get { return false; } }
201
202 public override OMV.Vector3 Size {
203 get
204 {
205 // Avatar capsule size is kept in the scale parameter.
206 return _size;
207 }
208
209 set {
210 // When an avatar's size is set, only the height is changed.
211 _size = value;
212 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
213 // replace with the default values.
214 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
215 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
216
217 ComputeAvatarScale(_size);
218 ComputeAvatarVolumeAndMass();
219 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
220 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
221
222 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
223 {
224 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
225 {
226 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
227 UpdatePhysicalMassProperties(RawMass);
228 // Make sure this change appears as a property update event
229 BulletSimAPI.PushUpdate2(PhysBody.ptr);
230 }
231 });
232
233 }
234 }
235
236 public override PrimitiveBaseShape Shape
237 {
238 set { BaseShape = value; }
239 }
240 // I want the physics engine to make an avatar capsule
241 public override BSPhysicsShapeType PreferredPhysicalShape
242 {
243 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
244 }
245
246 public override bool Grabbed {
247 set { _grabbed = value; }
248 }
249 public override bool Selected {
250 set { _selected = value; }
251 }
252 public override void CrossingFailure() { return; }
253 public override void link(PhysicsActor obj) { return; }
254 public override void delink() { return; }
255
256 // Set motion values to zero.
257 // Do it to the properties so the values get set in the physics engine.
258 // Push the setting of the values to the viewer.
259 // Called at taint time!
260 public override void ZeroMotion(bool inTaintTime)
261 {
262 _velocity = OMV.Vector3.Zero;
263 _velocityMotor.Zero();
264 _acceleration = OMV.Vector3.Zero;
265 _rotationalVelocity = OMV.Vector3.Zero;
266
267 // Zero some other properties directly into the physics engine
268 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
269 {
270 if (PhysBody.HasPhysicalBody)
271 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
272 });
273 }
274 public override void ZeroAngularMotion(bool inTaintTime)
275 {
276 _rotationalVelocity = OMV.Vector3.Zero;
277
278 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
279 {
280 if (PhysBody.HasPhysicalBody)
281 {
282 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
283 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
284 // The next also get rid of applied linear force but the linear velocity is untouched.
285 BulletSimAPI.ClearForces2(PhysBody.ptr);
286 }
287 });
288 }
289
290
291 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
292
293 public override OMV.Vector3 RawPosition
294 {
295 get { return _position; }
296 set { _position = value; }
297 }
298 public override OMV.Vector3 Position {
299 get {
300 // Don't refetch the position because this function is called a zillion times
301 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
302 return _position;
303 }
304 set {
305 _position = value;
306 PositionSanityCheck();
307
308 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
309 {
310 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
311 if (PhysBody.HasPhysicalBody)
312 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
313 });
314 }
315 }
316 public override OMV.Vector3 ForcePosition {
317 get {
318 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
319 return _position;
320 }
321 set {
322 _position = value;
323 PositionSanityCheck();
324 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
325 }
326 }
327
328
329 // Check that the current position is sane and, if not, modify the position to make it so.
330 // Check for being below terrain or on water.
331 // Returns 'true' of the position was made sane by some action.
332 private bool PositionSanityCheck()
333 {
334 bool ret = false;
335
336 // TODO: check for out of bounds
337 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
338 {
339 // The character is out of the known/simulated area.
340 // Upper levels of code will handle the transition to other areas so, for
341 // the time, we just ignore the position.
342 return ret;
343 }
344
345 // If below the ground, move the avatar up
346 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
347 if (Position.Z < terrainHeight)
348 {
349 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
350 _position.Z = terrainHeight + 2.0f;
351 ret = true;
352 }
353 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
354 {
355 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
356 if (Position.Z < waterHeight)
357 {
358 _position.Z = waterHeight;
359 ret = true;
360 }
361 }
362
363 return ret;
364 }
365
366 // A version of the sanity check that also makes sure a new position value is
367 // pushed back to the physics engine. This routine would be used by anyone
368 // who is not already pushing the value.
369 private bool PositionSanityCheck(bool inTaintTime)
370 {
371 bool ret = false;
372 if (PositionSanityCheck())
373 {
374 // The new position value must be pushed into the physics engine but we can't
375 // just assign to "Position" because of potential call loops.
376 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
377 {
378 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
379 if (PhysBody.HasPhysicalBody)
380 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
381 });
382 ret = true;
383 }
384 return ret;
385 }
386
387 public override float Mass { get { return _mass; } }
388
389 // used when we only want this prim's mass and not the linkset thing
390 public override float RawMass {
391 get {return _mass; }
392 }
393 public override void UpdatePhysicalMassProperties(float physMass)
394 {
395 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
396 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
397 }
398
399 public override OMV.Vector3 Force {
400 get { return _force; }
401 set {
402 _force = value;
403 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
404 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
405 {
406 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
407 if (PhysBody.HasPhysicalBody)
408 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
409 });
410 }
411 }
412
413 public bool TouchingGround()
414 {
415 bool ret = BulletSimAPI.RayCastGround(PhysicsScene.World.ptr,_position,_size.Z * 0.55f, PhysBody.ptr);
416 return ret;
417 }
418 // Avatars don't do vehicles
419 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
420 public override void VehicleFloatParam(int param, float value) { }
421 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
422 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
423 public override void VehicleFlags(int param, bool remove) { }
424
425 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
426 public override void SetVolumeDetect(int param) { return; }
427
428 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
429 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
430
431 // Sets the target in the motor. This starts the changing of the avatar's velocity.
432 public override OMV.Vector3 TargetVelocity
433 {
434 get
435 {
436 return _velocityMotor.TargetValue;
437 }
438 set
439 {
440 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
441
442 if (!_flying)
443 if ((value.Z >= 0.0001f) || (value.Z <= -0.0001f) || _velocity.Z < -0.0001f)
444 if (!TouchingGround())
445 value.Z = _velocity.Z;
446 if (_setAlwaysRun)
447 value *= 1.3f;
448
449 OMV.Vector3 targetVel = value;
450
451 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
452 {
453
454 _velocityMotor.Reset();
455 _velocityMotor.SetTarget(targetVel);
456 _velocityMotor.SetCurrent(_velocity);
457 _velocityMotor.Enabled = true;
458
459 // Make sure a property update happens next step so the motor gets incorporated.
460 BulletSimAPI.PushUpdate2(PhysBody.ptr);
461 });
462 }
463 }
464 // Directly setting velocity means this is what the user really wants now.
465 public override OMV.Vector3 Velocity {
466 get { return _velocity; }
467 set {
468 _velocity = value;
469 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
470 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
471 {
472 _velocityMotor.Reset();
473 _velocityMotor.SetCurrent(_velocity);
474 _velocityMotor.SetTarget(_velocity);
475 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
476 _velocityMotor.Enabled = false;
477
478 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
479 ForceVelocity = _velocity;
480 });
481 }
482 }
483 public override OMV.Vector3 ForceVelocity {
484 get { return _velocity; }
485 set {
486 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
487
488 _velocity = value;
489 // Depending on whether the avatar is moving or not, change the friction
490 // to keep the avatar from slipping around
491 if (_velocity.Length() == 0)
492 {
493 if (_currentFriction != BSParam.AvatarStandingFriction)
494 {
495 _currentFriction = BSParam.AvatarStandingFriction;
496 if (PhysBody.HasPhysicalBody)
497 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
498 }
499 }
500 else
501 {
502 if (_currentFriction != BSParam.AvatarFriction)
503 {
504 _currentFriction = BSParam.AvatarFriction;
505 if (PhysBody.HasPhysicalBody)
506 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
507 }
508 }
509 // Remember the set velocity so we can suppress the reduction by friction, ...
510 _appliedVelocity = value;
511
512 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
513 BulletSimAPI.Activate2(PhysBody.ptr, true);
514 }
515 }
516 public override OMV.Vector3 Torque {
517 get { return _torque; }
518 set { _torque = value;
519 }
520 }
521 public override float CollisionScore {
522 get { return _collisionScore; }
523 set { _collisionScore = value;
524 }
525 }
526 public override OMV.Vector3 Acceleration {
527 get { return _acceleration; }
528 set { _acceleration = value; }
529 }
530 public override OMV.Quaternion RawOrientation
531 {
532 get { return _orientation; }
533 set { _orientation = value; }
534 }
535 public override OMV.Quaternion Orientation {
536 get { return _orientation; }
537 set {
538 _orientation = value;
539 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
540 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
541 {
542 if (PhysBody.HasPhysicalBody)
543 {
544 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
545 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
546 }
547 });
548 }
549 }
550 // Go directly to Bullet to get/set the value.
551 public override OMV.Quaternion ForceOrientation
552 {
553 get
554 {
555 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
556 return _orientation;
557 }
558 set
559 {
560 _orientation = value;
561 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
562 }
563 }
564 public override int PhysicsActorType {
565 get { return _physicsActorType; }
566 set { _physicsActorType = value;
567 }
568 }
569 public override bool IsPhysical {
570 get { return _isPhysical; }
571 set { _isPhysical = value;
572 }
573 }
574 public override bool IsSolid {
575 get { return true; }
576 }
577 public override bool IsStatic {
578 get { return false; }
579 }
580 public override bool Flying {
581 get { return _flying; }
582 set {
583 _flying = value;
584
585 // simulate flying by changing the effect of gravity
586 Buoyancy = ComputeBuoyancyFromFlying(_flying);
587 }
588 }
589 // Flying is implimented by changing the avatar's buoyancy.
590 // Would this be done better with a vehicle type?
591 private float ComputeBuoyancyFromFlying(bool ifFlying) {
592 return ifFlying ? 1f : 0f;
593 }
594 public override bool
595 SetAlwaysRun {
596 get { return _setAlwaysRun; }
597 set { _setAlwaysRun = value; }
598 }
599 public override bool ThrottleUpdates {
600 get { return _throttleUpdates; }
601 set { _throttleUpdates = value; }
602 }
603 public override bool IsColliding {
604 get { return (CollidingStep == PhysicsScene.SimulationStep); }
605 set { _isColliding = value; }
606 }
607 public override bool CollidingGround {
608 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
609 set { CollidingGround = value; }
610 }
611 public override bool CollidingObj {
612 get { return _collidingObj; }
613 set { _collidingObj = value; }
614 }
615 public override bool FloatOnWater {
616 set {
617 _floatOnWater = value;
618 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
619 {
620 if (PhysBody.HasPhysicalBody)
621 {
622 if (_floatOnWater)
623 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
624 else
625 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
626 }
627 });
628 }
629 }
630 public override OMV.Vector3 RotationalVelocity {
631 get { return _rotationalVelocity; }
632 set { _rotationalVelocity = value; }
633 }
634 public override OMV.Vector3 ForceRotationalVelocity {
635 get { return _rotationalVelocity; }
636 set { _rotationalVelocity = value; }
637 }
638 public override bool Kinematic {
639 get { return _kinematic; }
640 set { _kinematic = value; }
641 }
642 // neg=fall quickly, 0=1g, 1=0g, pos=float up
643 public override float Buoyancy {
644 get { return _buoyancy; }
645 set { _buoyancy = value;
646 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
647 {
648 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
649 ForceBuoyancy = _buoyancy;
650 });
651 }
652 }
653 public override float ForceBuoyancy {
654 get { return _buoyancy; }
655 set {
656 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
657
658 _buoyancy = value;
659 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
660 // Buoyancy is faked by changing the gravity applied to the object
661 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
662 if (PhysBody.HasPhysicalBody)
663 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
664 }
665 }
666
667 // Used for MoveTo
668 public override OMV.Vector3 PIDTarget {
669 set { _PIDTarget = value; }
670 }
671 public override bool PIDActive {
672 set { _usePID = value; }
673 }
674 public override float PIDTau {
675 set { _PIDTau = value; }
676 }
677
678 // Used for llSetHoverHeight and maybe vehicle height
679 // Hover Height will override MoveTo target's Z
680 public override bool PIDHoverActive {
681 set { _useHoverPID = value; }
682 }
683 public override float PIDHoverHeight {
684 set { _PIDHoverHeight = value; }
685 }
686 public override PIDHoverType PIDHoverType {
687 set { _PIDHoverType = value; }
688 }
689 public override float PIDHoverTau {
690 set { _PIDHoverTao = value; }
691 }
692
693 // For RotLookAt
694 public override OMV.Quaternion APIDTarget { set { return; } }
695 public override bool APIDActive { set { return; } }
696 public override float APIDStrength { set { return; } }
697 public override float APIDDamping { set { return; } }
698
699 public override void AddForce(OMV.Vector3 force, bool pushforce) {
700 if (force.IsFinite())
701 {
702 _force.X += force.X;
703 _force.Y += force.Y;
704 _force.Z += force.Z;
705 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
706 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
707 {
708 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
709 if (PhysBody.HasPhysicalBody)
710 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
711 });
712 }
713 else
714 {
715 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader);
716 }
717 //m_lastUpdateSent = false;
718 }
719
720 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
721 }
722 public override void SetMomentum(OMV.Vector3 momentum) {
723 }
724
725 private void ComputeAvatarScale(OMV.Vector3 size)
726 {
727 OMV.Vector3 newScale = size;
728 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
729 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
730
731 // From the total height, remove the capsule half spheres that are at each end
732 // The 1.15f came from ODE. Not sure what this factors in.
733 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
734
735 // The total scale height is the central cylindar plus the caps on the two ends.
736 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
737
738 // Convert diameters to radii and height to half height -- the way Bullet expects it.
739 Scale = newScale / 2f;
740 }
741
742 // set _avatarVolume and _mass based on capsule size, _density and Scale
743 private void ComputeAvatarVolumeAndMass()
744 {
745 _avatarVolume = (float)(
746 Math.PI
747 * Scale.X
748 * Scale.Y // the area of capsule cylinder
749 * Scale.Z // times height of capsule cylinder
750 + 1.33333333f
751 * Math.PI
752 * Scale.X
753 * Math.Min(Scale.X, Scale.Y)
754 * Scale.Y // plus the volume of the capsule end caps
755 );
756 _mass = _avatarDensity * _avatarVolume;
757 }
758
759 // The physics engine says that properties have updated. Update same and inform
760 // the world that things have changed.
761 public override void UpdateProperties(EntityProperties entprop)
762 {
763 _position = entprop.Position;
764 _orientation = entprop.Rotation;
765 _velocity = entprop.Velocity;
766 _acceleration = entprop.Acceleration;
767 _rotationalVelocity = entprop.RotationalVelocity;
768
769 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
770 PositionSanityCheck(true);
771
772 if (_velocityMotor.Enabled)
773 {
774 // TODO: Decide if the step parameters should be changed depending on the avatar's
775 // state (flying, colliding, ...).
776
777 OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep);
778
779 // If falling, we keep the world's downward vector no matter what the other axis specify.
780 if (!Flying && !IsColliding)
781 {
782 stepVelocity.Z = entprop.Velocity.Z;
783 DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
784 }
785
786 // If the user has said stop and we've stopped applying velocity correction,
787 // the motor can be turned off. Set the velocity to zero so the zero motion is sent to the viewer.
788 if (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero)
789 {
790 stepVelocity = OMV.Vector3.Zero;
791 _velocityMotor.Enabled = false;
792 DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor);
793 }
794
795 _velocity = stepVelocity;
796 entprop.Velocity = _velocity;
797 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
798 }
799
800 // remember the current and last set values
801 LastEntityProperties = CurrentEntityProperties;
802 CurrentEntityProperties = entprop;
803
804 // Tell the linkset about value changes
805 Linkset.UpdateProperties(this, true);
806
807 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
808 // base.RequestPhysicsterseUpdate();
809
810 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
811 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
812 }
813}
814}