diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs | 814 |
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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | using OMV = OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSNPlugin | ||
36 | { | ||
37 | public 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 | } | ||