aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
diff options
context:
space:
mode:
authorteravus2012-12-23 15:21:25 -0500
committerteravus2012-12-23 15:21:25 -0500
commit92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf (patch)
treeeabcbb758a7512222e84cb51b51b6822cdbf561b /OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
parentRevert "Whitespace change to trigger bot" (diff)
downloadopensim-SC_OLD-92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf.zip
opensim-SC_OLD-92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf.tar.gz
opensim-SC_OLD-92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf.tar.bz2
opensim-SC_OLD-92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf.tar.xz
* Initial commit of BulletSimN (BulletSNPlugin). Purely C# implementation of BulletSim. This is designed to be /as close as possible/ to the BulletSim plugin while still being entirely in the managed space to make keeping it up to date easy as possible (no thinking work). This implementation is /slower/ then the c++ version just because it's fully managed, so it's not appropriate for huge sims, but it will run small ones OK. At the moment, it supports all known features of BulletSim. Think of it like.. POS but everything works. To use this plugin, set the physics plugin to BulletSimN.
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}