aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs3910
1 files changed, 3910 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
new file mode 100644
index 0000000..7e70db9
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
@@ -0,0 +1,3910 @@
1/* Copyright (c) Contributors, http://opensimulator.org/
2 * See CONTRIBUTORS.TXT for a full list of copyright holders.
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 * * Redistributions of source code must retain the above copyright
6 * notice, this list of conditions and the following disclaimer.
7 * * Redistributions in binary form must reproduce the above copyright
8 * notice, this list of conditions and the following disclaimer in the
9 * documentation and/or other materials provided with the distribution.
10 * * Neither the name of the OpenSimulator Project nor the
11 * names of its contributors may be used to endorse or promote products
12 * derived from this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Revised March 5th 2010 by Kitto Flora. ODEDynamics.cs
26 * rolled into ODEPrim.cs
27 */
28
29using System;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Runtime.InteropServices;
33using System.Threading;
34using log4net;
35using OpenMetaverse;
36using Ode.NET;
37using OpenSim.Framework;
38using OpenSim.Region.Physics.Manager;
39
40
41namespace OpenSim.Region.Physics.OdePlugin
42{
43 /// <summary>
44 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
45 /// </summary>
46
47 public class OdePrim : PhysicsActor
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private Vector3 _position;
52 private Vector3 _velocity;
53 private Vector3 _torque;
54 private Vector3 m_lastVelocity;
55 private Vector3 m_lastposition;
56 private Quaternion m_lastorientation = new Quaternion();
57 private Vector3 m_rotationalVelocity;
58 private Vector3 _size;
59 private Vector3 _acceleration;
60 // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f);
61 private Quaternion _orientation;
62 private Vector3 m_taintposition;
63 private Vector3 m_taintsize;
64 private Vector3 m_taintVelocity;
65 private Vector3 m_taintTorque;
66 private Quaternion m_taintrot;
67 private Vector3 m_rotateEnable = Vector3.One; // Current setting
68 private Vector3 m_rotateEnableRequest = Vector3.One; // Request from LSL
69 private bool m_rotateEnableUpdate = false;
70 private Vector3 m_lockX;
71 private Vector3 m_lockY;
72 private Vector3 m_lockZ;
73 private IntPtr Amotor = IntPtr.Zero;
74 private IntPtr AmotorX = IntPtr.Zero;
75 private IntPtr AmotorY = IntPtr.Zero;
76 private IntPtr AmotorZ = IntPtr.Zero;
77
78 private Vector3 m_PIDTarget;
79 private float m_PIDTau;
80 private float PID_D = 35f;
81 private float PID_G = 25f;
82 private bool m_usePID = false;
83
84 private Quaternion m_APIDTarget = new Quaternion();
85 private float m_APIDStrength = 0.5f;
86 private float m_APIDDamping = 0.5f;
87 private bool m_useAPID = false;
88
89 // These next 7 params apply to llSetHoverHeight(float height, integer water, float tau),
90 // do not confuse with VEHICLE HOVER
91
92 private float m_PIDHoverHeight;
93 private float m_PIDHoverTau;
94 private bool m_useHoverPID;
95 private PIDHoverType m_PIDHoverType = PIDHoverType.Ground;
96 private float m_targetHoverHeight;
97 private float m_groundHeight;
98 private float m_waterHeight;
99 private float m_buoyancy; //m_buoyancy set by llSetBuoyancy()
100
101 // private float m_tensor = 5f;
102 private int body_autodisable_frames = 20;
103
104
105 private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
106 | CollisionCategories.Space
107 | CollisionCategories.Body
108 | CollisionCategories.Character
109 );
110 private bool m_taintshape;
111 private bool m_taintPhysics;
112 private bool m_collidesLand = true;
113 private bool m_collidesWater;
114 public bool m_returnCollisions;
115
116 // Default we're a Geometry
117 private CollisionCategories m_collisionCategories = (CollisionCategories.Geom);
118
119 // Default, Collide with Other Geometries, spaces and Bodies
120 private CollisionCategories m_collisionFlags = m_default_collisionFlags;
121
122 public bool m_taintremove;
123 public bool m_taintdisable;
124 public bool m_disabled;
125 public bool m_taintadd;
126 public bool m_taintselected;
127 public bool m_taintCollidesWater;
128
129 public uint m_localID;
130
131 //public GCHandle gc;
132 private CollisionLocker ode;
133
134 private bool m_taintforce = false;
135 private bool m_taintaddangularforce = false;
136 private Vector3 m_force;
137 private List<Vector3> m_forcelist = new List<Vector3>();
138 private List<Vector3> m_angularforcelist = new List<Vector3>();
139
140 private IMesh _mesh;
141 private PrimitiveBaseShape _pbs;
142 private OdeScene _parent_scene;
143 public IntPtr m_targetSpace = IntPtr.Zero;
144 public IntPtr prim_geom;
145// public IntPtr prev_geom;
146 public IntPtr _triMeshData;
147
148 private IntPtr _linkJointGroup = IntPtr.Zero;
149 private PhysicsActor _parent;
150 private PhysicsActor m_taintparent;
151
152 private List<OdePrim> childrenPrim = new List<OdePrim>();
153
154 private bool iscolliding;
155 private bool m_isphysical;
156 private bool m_isSelected;
157
158 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
159
160 private bool m_throttleUpdates;
161 private int throttleCounter;
162 public int m_interpenetrationcount;
163 public float m_collisionscore;
164 public int m_roundsUnderMotionThreshold;
165 private int m_crossingfailures;
166
167 public bool outofBounds;
168 private float m_density = 10.000006836f; // Aluminum g/cm3;
169
170 public bool _zeroFlag; // if body has been stopped
171 private bool m_lastUpdateSent;
172
173 public IntPtr Body = IntPtr.Zero;
174 public String m_primName;
175 private Vector3 _target_velocity;
176 public d.Mass pMass;
177
178 public int m_eventsubscription;
179 private CollisionEventUpdate CollisionEventsThisFrame;
180
181 private IntPtr m_linkJoint = IntPtr.Zero;
182
183 public volatile bool childPrim;
184
185 internal int m_material = (int)Material.Wood;
186
187 private int frcount = 0; // Used to limit dynamics debug output to
188 private int revcount = 0; // Reverse motion while > 0
189
190 private IntPtr m_body = IntPtr.Zero;
191
192 // Vehicle properties ============================================================================================
193 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
194 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
195 private VehicleFlag m_flags = (VehicleFlag) 0; // Bit settings:
196 // HOVER_TERRAIN_ONLY
197 // HOVER_GLOBAL_HEIGHT
198 // NO_DEFLECTION_UP
199 // HOVER_WATER_ONLY
200 // HOVER_UP_ONLY
201 // LIMIT_MOTOR_UP
202 // LIMIT_ROLL_ONLY
203
204 // Linear properties
205 private Vector3 m_linearMotorDirection = Vector3.Zero; // (was m_linearMotorDirectionLASTSET) the (local) Velocity
206 //requested by LSL
207 private float m_linearMotorTimescale = 0; // Motor Attack rate set by LSL
208 private float m_linearMotorDecayTimescale = 0; // Motor Decay rate set by LSL
209 private Vector3 m_linearFrictionTimescale = Vector3.Zero; // General Friction set by LSL
210
211 private Vector3 m_lLinMotorDVel = Vector3.Zero; // decayed motor
212 private Vector3 m_lLinObjectVel = Vector3.Zero; // local frame object velocity
213 private Vector3 m_wLinObjectVel = Vector3.Zero; // world frame object velocity
214
215 //Angular properties
216 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
217
218 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
219 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
220 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
221
222 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
223// private Vector3 m_angObjectVel = Vector3.Zero; // current body angular velocity
224 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
225
226 //Deflection properties
227 // private float m_angularDeflectionEfficiency = 0;
228 // private float m_angularDeflectionTimescale = 0;
229 // private float m_linearDeflectionEfficiency = 0;
230 // private float m_linearDeflectionTimescale = 0;
231
232 //Banking properties
233 // private float m_bankingEfficiency = 0;
234 // private float m_bankingMix = 0;
235 // private float m_bankingTimescale = 0;
236
237 //Hover and Buoyancy properties
238 private float m_VhoverHeight = 0f;
239// private float m_VhoverEfficiency = 0f;
240 private float m_VhoverTimescale = 0f;
241 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
242 private float m_VehicleBuoyancy = 0f; // Set by VEHICLE_BUOYANCY, for a vehicle.
243 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
244 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
245 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
246
247 //Attractor properties
248 private float m_verticalAttractionEfficiency = 1.0f; // damped
249 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
250
251
252
253
254
255
256 public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
257 Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode)
258 {
259 ode = dode;
260 if (!pos.IsFinite())
261 {
262 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
263 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
264 m_log.Warn("[PHYSICS]: Got nonFinite Object create Position");
265 }
266
267 _position = pos;
268 m_taintposition = pos;
269 PID_D = parent_scene.bodyPIDD;
270 PID_G = parent_scene.bodyPIDG;
271 m_density = parent_scene.geomDefaultDensity;
272 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
273 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
274
275
276 prim_geom = IntPtr.Zero;
277// prev_geom = IntPtr.Zero;
278
279 if (!pos.IsFinite())
280 {
281 size = new Vector3(0.5f, 0.5f, 0.5f);
282 m_log.Warn("[PHYSICS]: Got nonFinite Object create Size");
283 }
284
285 if (size.X <= 0) size.X = 0.01f;
286 if (size.Y <= 0) size.Y = 0.01f;
287 if (size.Z <= 0) size.Z = 0.01f;
288
289 _size = size;
290 m_taintsize = _size;
291
292 if (!QuaternionIsFinite(rotation))
293 {
294 rotation = Quaternion.Identity;
295 m_log.Warn("[PHYSICS]: Got nonFinite Object create Rotation");
296 }
297
298 _orientation = rotation;
299 m_taintrot = _orientation;
300 _mesh = mesh;
301 _pbs = pbs;
302
303 _parent_scene = parent_scene;
304 m_targetSpace = (IntPtr)0;
305
306// if (pos.Z < 0)
307 if (pos.Z < parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y))
308 m_isphysical = false;
309 else
310 {
311 m_isphysical = pisPhysical;
312 // If we're physical, we need to be in the master space for now.
313 // linksets *should* be in a space together.. but are not currently
314 if (m_isphysical)
315 m_targetSpace = _parent_scene.space;
316 }
317 m_primName = primName;
318 m_taintadd = true;
319 _parent_scene.AddPhysicsActorTaint(this);
320 // don't do .add() here; old geoms get recycled with the same hash
321 }
322
323 public override int PhysicsActorType
324 {
325 get { return (int) ActorTypes.Prim; }
326 set { return; }
327 }
328
329 public override bool SetAlwaysRun
330 {
331 get { return false; }
332 set { return; }
333 }
334
335 public override uint LocalID
336 {
337 set {
338 //m_log.Info("[PHYSICS]: Setting TrackerID: " + value);
339 m_localID = value; }
340 }
341
342 public override bool Grabbed
343 {
344 set { return; }
345 }
346
347 public override bool Selected
348 {
349 set {
350
351//Console.WriteLine("Sel {0} {1} {2}", m_primName, value, m_isphysical);
352 // This only makes the object not collidable if the object
353 // is physical or the object is modified somehow *IN THE FUTURE*
354 // without this, if an avatar selects prim, they can walk right
355 // through it while it's selected
356 m_collisionscore = 0;
357 if ((m_isphysical && !_zeroFlag) || !value)
358 {
359 m_taintselected = value;
360 _parent_scene.AddPhysicsActorTaint(this);
361 }
362 else
363 {
364 m_taintselected = value;
365 m_isSelected = value;
366 }
367 if(m_isSelected) disableBodySoft();
368 }
369 }
370
371 public override bool IsPhysical
372 {
373 get { return m_isphysical; }
374 set
375 {
376 m_isphysical = value;
377 if (!m_isphysical)
378 { // Zero the remembered last velocity
379 m_lastVelocity = Vector3.Zero;
380 if (m_type != Vehicle.TYPE_NONE) Halt();
381 }
382 }
383 }
384
385 public void setPrimForRemoval()
386 {
387 m_taintremove = true;
388 }
389
390 public override bool Flying
391 {
392 // no flying prims for you
393 get { return false; }
394 set { }
395 }
396
397 public override bool IsColliding
398 {
399 get { return iscolliding; }
400 set { iscolliding = value; }
401 }
402
403 public override bool CollidingGround
404 {
405 get { return false; }
406 set { return; }
407 }
408
409 public override bool CollidingObj
410 {
411 get { return false; }
412 set { return; }
413 }
414
415 public override bool ThrottleUpdates
416 {
417 get { return m_throttleUpdates; }
418 set { m_throttleUpdates = value; }
419 }
420
421 public override bool Stopped
422 {
423 get { return _zeroFlag; }
424 }
425
426 public override Vector3 Position
427 {
428 get { return _position; }
429
430 set { _position = value;
431 //m_log.Info("[PHYSICS]: " + _position.ToString());
432 }
433 }
434
435 public override Vector3 Size
436 {
437 get { return _size; }
438 set
439 {
440 if (value.IsFinite())
441 {
442 _size = value;
443 }
444 else
445 {
446 m_log.Warn("[PHYSICS]: Got NaN Size on object");
447 }
448 }
449 }
450
451 public override float Mass
452 {
453 get { return CalculateMass(); }
454 }
455
456 public override Vector3 Force
457 {
458 //get { return Vector3.Zero; }
459 get { return m_force; }
460 set
461 {
462 if (value.IsFinite())
463 {
464 m_force = value;
465 }
466 else
467 {
468 m_log.Warn("[PHYSICS]: NaN in Force Applied to an Object");
469 }
470 }
471 }
472
473 public override int VehicleType
474 {
475 get { return (int)m_type; }
476 set { ProcessTypeChange((Vehicle)value); }
477 }
478
479 public override void VehicleFloatParam(int param, float value)
480 {
481 ProcessFloatVehicleParam((Vehicle) param, value);
482 }
483
484 public override void VehicleVectorParam(int param, Vector3 value)
485 {
486 ProcessVectorVehicleParam((Vehicle) param, value);
487 }
488
489 public override void VehicleRotationParam(int param, Quaternion rotation)
490 {
491 ProcessRotationVehicleParam((Vehicle) param, rotation);
492 }
493
494 public override void VehicleFlags(int param, bool remove)
495 {
496 ProcessVehicleFlags(param, remove);
497 }
498
499 public override void SetVolumeDetect(int param)
500 {
501 lock (_parent_scene.OdeLock)
502 {
503 m_isVolumeDetect = (param!=0);
504 }
505 }
506
507 public override Vector3 CenterOfMass
508 {
509 get { return Vector3.Zero; }
510 }
511
512 public override Vector3 GeometricCenter
513 {
514 get { return Vector3.Zero; }
515 }
516
517 public override PrimitiveBaseShape Shape
518 {
519 set
520 {
521 _pbs = value;
522 m_taintshape = true;
523 }
524 }
525
526 public override Vector3 Velocity
527 {
528 get
529 {
530 // Averate previous velocity with the new one so
531 // client object interpolation works a 'little' better
532 if (_zeroFlag)
533 return Vector3.Zero;
534
535 Vector3 returnVelocity = Vector3.Zero;
536 returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2;
537 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2;
538 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2;
539 return returnVelocity;
540 }
541 set
542 {
543 if (value.IsFinite())
544 {
545 _velocity = value;
546
547 m_taintVelocity = value;
548 _parent_scene.AddPhysicsActorTaint(this);
549 }
550 else
551 {
552 m_log.Warn("[PHYSICS]: Got NaN Velocity in Object");
553 }
554
555 }
556 }
557
558 public override Vector3 Torque
559 {
560 get
561 {
562 if (!m_isphysical || Body == IntPtr.Zero)
563 return Vector3.Zero;
564
565 return _torque;
566 }
567
568 set
569 {
570 if (value.IsFinite())
571 {
572 m_taintTorque = value;
573 _parent_scene.AddPhysicsActorTaint(this);
574 }
575 else
576 {
577 m_log.Warn("[PHYSICS]: Got NaN Torque in Object");
578 }
579 }
580 }
581
582 public override float CollisionScore
583 {
584 get { return m_collisionscore; }
585 set { m_collisionscore = value; }
586 }
587
588 public override bool Kinematic
589 {
590 get { return false; }
591 set { }
592 }
593
594 public override Quaternion Orientation
595 {
596 get { return _orientation; }
597 set
598 {
599 if (QuaternionIsFinite(value))
600 {
601 _orientation = value;
602 }
603 else
604 m_log.Warn("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object");
605
606 }
607 }
608
609
610 public override bool FloatOnWater
611 {
612 set {
613 m_taintCollidesWater = value;
614 _parent_scene.AddPhysicsActorTaint(this);
615 }
616 }
617
618 public override void SetMomentum(Vector3 momentum)
619 {
620 }
621
622 public override Vector3 PIDTarget
623 {
624 set
625 {
626 if (value.IsFinite())
627 {
628 m_PIDTarget = value;
629 }
630 else
631 m_log.Warn("[PHYSICS]: Got NaN PIDTarget from Scene on Object");
632 }
633 }
634 public override bool PIDActive { set { m_usePID = value; } }
635 public override float PIDTau { set { m_PIDTau = value; } }
636
637 // For RotLookAt
638 public override Quaternion APIDTarget { set { m_APIDTarget = value; } }
639 public override bool APIDActive { set { m_useAPID = value; } }
640 public override float APIDStrength { set { m_APIDStrength = value; } }
641 public override float APIDDamping { set { m_APIDDamping = value; } }
642
643 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
644 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
645 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
646 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
647
648 internal static bool QuaternionIsFinite(Quaternion q)
649 {
650 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
651 return false;
652 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
653 return false;
654 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
655 return false;
656 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
657 return false;
658 return true;
659 }
660
661 public override Vector3 Acceleration // client updates read data via here
662 {
663 get { return _acceleration; }
664 }
665
666
667 public void SetAcceleration(Vector3 accel) // No one calls this, and it would not do anything.
668 {
669 _acceleration = accel;
670 }
671
672 public override void AddForce(Vector3 force, bool pushforce)
673 {
674 if (force.IsFinite())
675 {
676 lock (m_forcelist)
677 m_forcelist.Add(force);
678
679 m_taintforce = true;
680 }
681 else
682 {
683 m_log.Warn("[PHYSICS]: Got Invalid linear force vector from Scene in Object");
684 }
685 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
686 }
687
688 public override void AddAngularForce(Vector3 force, bool pushforce)
689 {
690 if (force.IsFinite())
691 {
692 m_angularforcelist.Add(force);
693 m_taintaddangularforce = true;
694 }
695 else
696 {
697 m_log.Warn("[PHYSICS]: Got Invalid Angular force vector from Scene in Object");
698 }
699 }
700
701 public override Vector3 RotationalVelocity
702 {
703 get
704 {
705 return m_rotationalVelocity;
706 }
707 set
708 {
709 if (value.IsFinite())
710 {
711 m_rotationalVelocity = value;
712 }
713 else
714 {
715 m_log.Warn("[PHYSICS]: Got NaN RotationalVelocity in Object");
716 }
717 }
718 }
719
720 public override void CrossingFailure()
721 {
722 m_crossingfailures++;
723 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
724 {
725 base.RaiseOutOfBounds(_position);
726 return;
727 }
728 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
729 {
730 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + m_primName);
731 }
732 }
733
734 public override float Buoyancy
735 {
736 get { return m_buoyancy; }
737// set { m_buoyancy = value; }
738 set {
739 m_buoyancy = value;
740
741 Console.WriteLine("m_buoyancy={0}", m_buoyancy);
742 }
743 }
744
745 public override void link(PhysicsActor obj)
746 {
747 m_taintparent = obj;
748 }
749
750 public override void delink()
751 {
752 m_taintparent = null;
753 }
754
755 public override void LockAngularMotion(Vector3 axis)
756 {
757 // This is actually ROTATION ENABLE, not a lock.
758 // default is <1,1,1> which is all enabled.
759 // The lock value is updated inside Move(), no point in using the taint system.
760 // OS 'm_taintAngularLock' etc change to m_rotateEnable.
761 if (axis.IsFinite())
762 {
763 axis.X = (axis.X > 0) ? 1f : 0f;
764 axis.Y = (axis.Y > 0) ? 1f : 0f;
765 axis.Z = (axis.Z > 0) ? 1f : 0f;
766 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
767 m_rotateEnableRequest = axis;
768 m_rotateEnableUpdate = true;
769 }
770 else
771 {
772 m_log.Warn("[PHYSICS]: Got NaN locking axis from Scene on Object");
773 }
774 }
775
776
777 public void SetGeom(IntPtr geom)
778 {
779 if(prim_geom != IntPtr.Zero)
780 {
781 // Remove any old entries
782//string tPA;
783//_parent_scene.geom_name_map.TryGetValue(prim_geom, out tPA);
784//Console.WriteLine("**** Remove {0}", tPA);
785 if(_parent_scene.geom_name_map.ContainsKey(prim_geom)) _parent_scene.geom_name_map.Remove(prim_geom);
786 if(_parent_scene.actor_name_map.ContainsKey(prim_geom)) _parent_scene.actor_name_map.Remove(prim_geom);
787 d.GeomDestroy(prim_geom);
788 }
789
790 prim_geom = geom;
791//Console.WriteLine("SetGeom to " + prim_geom + " for " + m_primName);
792 if (prim_geom != IntPtr.Zero)
793 {
794 _parent_scene.geom_name_map[prim_geom] = this.m_primName;
795 _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
796 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
797 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
798//Console.WriteLine("**** Create {2} Dicts: actor={0} name={1}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, this.m_primName);
799 }
800
801 if (childPrim)
802 {
803 if (_parent != null && _parent is OdePrim)
804 {
805 OdePrim parent = (OdePrim)_parent;
806//Console.WriteLine("SetGeom calls ChildSetGeom");
807 parent.ChildSetGeom(this);
808 }
809 }
810 //m_log.Warn("Setting Geom to: " + prim_geom);
811 }
812
813 public void enableBodySoft()
814 {
815 if (!childPrim)
816 {
817 if (m_isphysical && Body != IntPtr.Zero)
818 {
819 d.BodyEnable(Body);
820 if (m_type != Vehicle.TYPE_NONE)
821 Enable(Body, _parent_scene);
822 }
823
824 m_disabled = false;
825 }
826 }
827
828 public void disableBodySoft()
829 {
830 m_disabled = true;
831
832 if (m_isphysical && Body != IntPtr.Zero)
833 {
834 d.BodyDisable(Body);
835 Halt();
836 }
837 }
838
839 public void enableBody()
840 {
841 // Don't enable this body if we're a child prim
842 // this should be taken care of in the parent function not here
843 if (!childPrim)
844 {
845 // Sets the geom to a body
846 Body = d.BodyCreate(_parent_scene.world);
847
848 setMass();
849 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
850 d.Quaternion myrot = new d.Quaternion();
851 myrot.X = _orientation.X;
852 myrot.Y = _orientation.Y;
853 myrot.Z = _orientation.Z;
854 myrot.W = _orientation.W;
855 d.BodySetQuaternion(Body, ref myrot);
856 d.GeomSetBody(prim_geom, Body);
857 m_collisionCategories |= CollisionCategories.Body;
858 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
859
860 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
861 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
862
863 d.BodySetAutoDisableFlag(Body, true);
864 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
865
866 // disconnect from world gravity so we can apply buoyancy
867 d.BodySetGravityMode (Body, false);
868
869 m_interpenetrationcount = 0;
870 m_collisionscore = 0;
871 m_disabled = false;
872
873 if (m_type != Vehicle.TYPE_NONE)
874 {
875 Enable(Body, _parent_scene);
876 }
877
878 _parent_scene.addActivePrim(this);
879 }
880 }
881
882 #region Mass Calculation
883
884 private float CalculateMass()
885 {
886 float volume = 0;
887
888 // No material is passed to the physics engines yet.. soo..
889 // we're using the m_density constant in the class definition
890
891 float returnMass = 0;
892
893 switch (_pbs.ProfileShape)
894 {
895 case ProfileShape.Square:
896 // Profile Volume
897
898 volume = _size.X*_size.Y*_size.Z;
899
900 // If the user has 'hollowed out'
901 // ProfileHollow is one of those 0 to 50000 values :P
902 // we like percentages better.. so turning into a percentage
903
904 if (((float) _pbs.ProfileHollow/50000f) > 0.0)
905 {
906 float hollowAmount = (float) _pbs.ProfileHollow/50000f;
907
908 // calculate the hollow volume by it's shape compared to the prim shape
909 float hollowVolume = 0;
910 switch (_pbs.HollowShape)
911 {
912 case HollowShape.Square:
913 case HollowShape.Same:
914 // Cube Hollow volume calculation
915 float hollowsizex = _size.X*hollowAmount;
916 float hollowsizey = _size.Y*hollowAmount;
917 float hollowsizez = _size.Z*hollowAmount;
918 hollowVolume = hollowsizex*hollowsizey*hollowsizez;
919 break;
920
921 case HollowShape.Circle:
922 // Hollow shape is a perfect cyllinder in respect to the cube's scale
923 // Cyllinder hollow volume calculation
924 float hRadius = _size.X/2;
925 float hLength = _size.Z;
926
927 // pi * r2 * h
928 hollowVolume = ((float) (Math.PI*Math.Pow(hRadius, 2)*hLength)*hollowAmount);
929 break;
930
931 case HollowShape.Triangle:
932 // Equilateral Triangular Prism volume hollow calculation
933 // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
934
935 float aLength = _size.Y;
936 // 1/2 abh
937 hollowVolume = (float) ((0.5*aLength*_size.X*_size.Z)*hollowAmount);
938 break;
939
940 default:
941 hollowVolume = 0;
942 break;
943 }
944 volume = volume - hollowVolume;
945 }
946
947 break;
948 case ProfileShape.Circle:
949 if (_pbs.PathCurve == (byte)Extrusion.Straight)
950 {
951 // Cylinder
952 float volume1 = (float)(Math.PI * Math.Pow(_size.X/2, 2) * _size.Z);
953 float volume2 = (float)(Math.PI * Math.Pow(_size.Y/2, 2) * _size.Z);
954
955 // Approximating the cylinder's irregularity.
956 if (volume1 > volume2)
957 {
958 volume = (float)volume1 - (volume1 - volume2);
959 }
960 else if (volume2 > volume1)
961 {
962 volume = (float)volume2 - (volume2 - volume1);
963 }
964 else
965 {
966 // Regular cylinder
967 volume = volume1;
968 }
969 }
970 else
971 {
972 // We don't know what the shape is yet, so use default
973 volume = _size.X * _size.Y * _size.Z;
974 }
975 // If the user has 'hollowed out'
976 // ProfileHollow is one of those 0 to 50000 values :P
977 // we like percentages better.. so turning into a percentage
978
979 if (((float)_pbs.ProfileHollow / 50000f) > 0.0)
980 {
981 float hollowAmount = (float)_pbs.ProfileHollow / 50000f;
982
983 // calculate the hollow volume by it's shape compared to the prim shape
984 float hollowVolume = 0;
985 switch (_pbs.HollowShape)
986 {
987 case HollowShape.Same:
988 case HollowShape.Circle:
989 // Hollow shape is a perfect cyllinder in respect to the cube's scale
990 // Cyllinder hollow volume calculation
991 float hRadius = _size.X / 2;
992 float hLength = _size.Z;
993
994 // pi * r2 * h
995 hollowVolume = ((float)(Math.PI * Math.Pow(hRadius, 2) * hLength) * hollowAmount);
996 break;
997
998 case HollowShape.Square:
999 // Cube Hollow volume calculation
1000 float hollowsizex = _size.X * hollowAmount;
1001 float hollowsizey = _size.Y * hollowAmount;
1002 float hollowsizez = _size.Z * hollowAmount;
1003 hollowVolume = hollowsizex * hollowsizey * hollowsizez;
1004 break;
1005
1006 case HollowShape.Triangle:
1007 // Equilateral Triangular Prism volume hollow calculation
1008 // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
1009
1010 float aLength = _size.Y;
1011 // 1/2 abh
1012 hollowVolume = (float)((0.5 * aLength * _size.X * _size.Z) * hollowAmount);
1013 break;
1014
1015 default:
1016 hollowVolume = 0;
1017 break;
1018 }
1019 volume = volume - hollowVolume;
1020 }
1021 break;
1022
1023 case ProfileShape.HalfCircle:
1024 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1025 {
1026 if (_size.X == _size.Y && _size.Y == _size.Z)
1027 {
1028 // regular sphere
1029 // v = 4/3 * pi * r^3
1030 float sradius3 = (float)Math.Pow((_size.X / 2), 3);
1031 volume = (float)((4f / 3f) * Math.PI * sradius3);
1032 }
1033 else
1034 {
1035 // we treat this as a box currently
1036 volume = _size.X * _size.Y * _size.Z;
1037 }
1038 }
1039 else
1040 {
1041 // We don't know what the shape is yet, so use default
1042 volume = _size.X * _size.Y * _size.Z;
1043 }
1044 break;
1045
1046 case ProfileShape.EquilateralTriangle:
1047 /*
1048 v = (abs((xB*yA-xA*yB)+(xC*yB-xB*yC)+(xA*yC-xC*yA))/2) * h
1049
1050 // seed mesh
1051 Vertex MM = new Vertex(-0.25f, -0.45f, 0.0f);
1052 Vertex PM = new Vertex(+0.5f, 0f, 0.0f);
1053 Vertex PP = new Vertex(-0.25f, +0.45f, 0.0f);
1054 */
1055 float xA = -0.25f * _size.X;
1056 float yA = -0.45f * _size.Y;
1057
1058 float xB = 0.5f * _size.X;
1059 float yB = 0;
1060
1061 float xC = -0.25f * _size.X;
1062 float yC = 0.45f * _size.Y;
1063
1064 volume = (float)((Math.Abs((xB * yA - xA * yB) + (xC * yB - xB * yC) + (xA * yC - xC * yA)) / 2) * _size.Z);
1065
1066 // If the user has 'hollowed out'
1067 // ProfileHollow is one of those 0 to 50000 values :P
1068 // we like percentages better.. so turning into a percentage
1069 float fhollowFactor = ((float)_pbs.ProfileHollow / 1.9f);
1070 if (((float)fhollowFactor / 50000f) > 0.0)
1071 {
1072 float hollowAmount = (float)fhollowFactor / 50000f;
1073
1074 // calculate the hollow volume by it's shape compared to the prim shape
1075 float hollowVolume = 0;
1076 switch (_pbs.HollowShape)
1077 {
1078 case HollowShape.Same:
1079 case HollowShape.Triangle:
1080 // Equilateral Triangular Prism volume hollow calculation
1081 // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
1082
1083 float aLength = _size.Y;
1084 // 1/2 abh
1085 hollowVolume = (float)((0.5 * aLength * _size.X * _size.Z) * hollowAmount);
1086 break;
1087
1088 case HollowShape.Square:
1089 // Cube Hollow volume calculation
1090 float hollowsizex = _size.X * hollowAmount;
1091 float hollowsizey = _size.Y * hollowAmount;
1092 float hollowsizez = _size.Z * hollowAmount;
1093 hollowVolume = hollowsizex * hollowsizey * hollowsizez;
1094 break;
1095
1096 case HollowShape.Circle:
1097 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1098 // Cyllinder hollow volume calculation
1099 float hRadius = _size.X / 2;
1100 float hLength = _size.Z;
1101
1102 // pi * r2 * h
1103 hollowVolume = ((float)((Math.PI * Math.Pow(hRadius, 2) * hLength)/2) * hollowAmount);
1104 break;
1105
1106 default:
1107 hollowVolume = 0;
1108 break;
1109 }
1110 volume = volume - hollowVolume;
1111 }
1112 break;
1113
1114 default:
1115 // we don't have all of the volume formulas yet so
1116 // use the common volume formula for all
1117 volume = _size.X*_size.Y*_size.Z;
1118 break;
1119 }
1120
1121 // Calculate Path cut effect on volume
1122 // Not exact, in the triangle hollow example
1123 // They should never be zero or less then zero..
1124 // we'll ignore it if it's less then zero
1125
1126 // ProfileEnd and ProfileBegin are values
1127 // from 0 to 50000
1128
1129 // Turning them back into percentages so that I can cut that percentage off the volume
1130
1131 float PathCutEndAmount = _pbs.ProfileEnd;
1132 float PathCutStartAmount = _pbs.ProfileBegin;
1133 if (((PathCutStartAmount + PathCutEndAmount)/50000f) > 0.0f)
1134 {
1135 float pathCutAmount = ((PathCutStartAmount + PathCutEndAmount)/50000f);
1136
1137 // Check the return amount for sanity
1138 if (pathCutAmount >= 0.99f)
1139 pathCutAmount = 0.99f;
1140
1141 volume = volume - (volume*pathCutAmount);
1142 }
1143 UInt16 taperX = _pbs.PathScaleX;
1144 UInt16 taperY = _pbs.PathScaleY;
1145 float taperFactorX = 0;
1146 float taperFactorY = 0;
1147
1148 // Mass = density * volume
1149 if (taperX != 100)
1150 {
1151 if (taperX > 100)
1152 {
1153 taperFactorX = 1.0f - ((float)taperX / 200);
1154 //m_log.Warn("taperTopFactorX: " + extr.taperTopFactorX.ToString());
1155 }
1156 else
1157 {
1158 taperFactorX = 1.0f - ((100 - (float)taperX) / 100);
1159 //m_log.Warn("taperBotFactorX: " + extr.taperBotFactorX.ToString());
1160 }
1161 volume = (float)volume * ((taperFactorX / 3f) + 0.001f);
1162 }
1163
1164 if (taperY != 100)
1165 {
1166 if (taperY > 100)
1167 {
1168 taperFactorY = 1.0f - ((float)taperY / 200);
1169 //m_log.Warn("taperTopFactorY: " + extr.taperTopFactorY.ToString());
1170 }
1171 else
1172 {
1173 taperFactorY = 1.0f - ((100 - (float)taperY) / 100);
1174 //m_log.Warn("taperBotFactorY: " + extr.taperBotFactorY.ToString());
1175 }
1176 volume = (float)volume * ((taperFactorY / 3f) + 0.001f);
1177 }
1178 returnMass = m_density*volume;
1179 if (returnMass <= 0) returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
1180
1181
1182
1183 // Recursively calculate mass
1184 bool HasChildPrim = false;
1185 lock (childrenPrim)
1186 {
1187 if (childrenPrim.Count > 0)
1188 {
1189 HasChildPrim = true;
1190 }
1191
1192 }
1193 if (HasChildPrim)
1194 {
1195 OdePrim[] childPrimArr = new OdePrim[0];
1196
1197 lock (childrenPrim)
1198 childPrimArr = childrenPrim.ToArray();
1199
1200 for (int i = 0; i < childPrimArr.Length; i++)
1201 {
1202 if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove)
1203 returnMass += childPrimArr[i].CalculateMass();
1204 // failsafe, this shouldn't happen but with OpenSim, you never know :)
1205 if (i > 256)
1206 break;
1207 }
1208 }
1209 if (returnMass > _parent_scene.maximumMassObject)
1210 returnMass = _parent_scene.maximumMassObject;
1211 return returnMass;
1212 }// end CalculateMass
1213
1214 #endregion
1215
1216 public void setMass()
1217 {
1218 if (Body != (IntPtr) 0)
1219 {
1220 float newmass = CalculateMass();
1221
1222 //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString());
1223
1224 d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z);
1225 d.BodySetMass(Body, ref pMass);
1226 }
1227 }
1228
1229 public void disableBody()
1230 {
1231 //this kills the body so things like 'mesh' can re-create it.
1232 lock (this)
1233 {
1234 if (!childPrim)
1235 {
1236 if (Body != IntPtr.Zero)
1237 {
1238 _parent_scene.remActivePrim(this);
1239 m_collisionCategories &= ~CollisionCategories.Body;
1240 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1241
1242 if (prim_geom != IntPtr.Zero)
1243 {
1244 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1245 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1246 }
1247
1248
1249 d.BodyDestroy(Body);
1250 lock (childrenPrim)
1251 {
1252 if (childrenPrim.Count > 0)
1253 {
1254 foreach (OdePrim prm in childrenPrim)
1255 {
1256 _parent_scene.remActivePrim(prm);
1257 prm.Body = IntPtr.Zero;
1258 }
1259 }
1260 }
1261 Body = IntPtr.Zero;
1262 }
1263 }
1264 else
1265 {
1266 _parent_scene.remActivePrim(this);
1267
1268 m_collisionCategories &= ~CollisionCategories.Body;
1269 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1270
1271 if (prim_geom != IntPtr.Zero)
1272 {
1273 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1274 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1275 }
1276
1277
1278 Body = IntPtr.Zero;
1279 }
1280 }
1281 m_disabled = true;
1282 m_collisionscore = 0;
1283 }
1284
1285 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
1286
1287 public void setMesh(OdeScene parent_scene, IMesh mesh)
1288 {
1289 // This sleeper is there to moderate how long it takes between
1290 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
1291
1292 //Thread.Sleep(10);
1293
1294 //Kill Body so that mesh can re-make the geom
1295 if (IsPhysical && Body != IntPtr.Zero)
1296 {
1297 if (childPrim)
1298 {
1299 if (_parent != null)
1300 {
1301 OdePrim parent = (OdePrim)_parent;
1302 parent.ChildDelink(this);
1303 }
1304 }
1305 else
1306 {
1307 disableBody();
1308 }
1309 }
1310
1311 IntPtr vertices, indices;
1312 int vertexCount, indexCount;
1313 int vertexStride, triStride;
1314 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
1315 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
1316
1317 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
1318 if (m_MeshToTriMeshMap.ContainsKey(mesh))
1319 {
1320 _triMeshData = m_MeshToTriMeshMap[mesh];
1321 }
1322 else
1323 {
1324 _triMeshData = d.GeomTriMeshDataCreate();
1325
1326 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
1327 d.GeomTriMeshDataPreprocess(_triMeshData);
1328 m_MeshToTriMeshMap[mesh] = _triMeshData;
1329 }
1330
1331 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1332 try
1333 {
1334 if (prim_geom == IntPtr.Zero)
1335 {
1336 SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null));
1337 }
1338 }
1339 catch (AccessViolationException)
1340 {
1341 m_log.Error("[PHYSICS]: MESH LOCKED");
1342 return;
1343 }
1344
1345
1346 // if (IsPhysical && Body == (IntPtr) 0)
1347 // {
1348 // Recreate the body
1349 // m_interpenetrationcount = 0;
1350 // m_collisionscore = 0;
1351
1352 // enableBody();
1353 // }
1354 }
1355
1356 public void ProcessTaints(float timestep) //=============================================================================
1357 {
1358 if (m_taintadd)
1359 {
1360 changeadd(timestep);
1361 }
1362
1363 if (prim_geom != IntPtr.Zero)
1364 {
1365 if (!_position.ApproxEquals(m_taintposition, 0f))
1366 changemove(timestep);
1367
1368 if (m_taintrot != _orientation)
1369 {
1370 if(childPrim && IsPhysical) // For physical child prim...
1371 {
1372 rotate(timestep);
1373 // KF: ODE will also rotate the parent prim!
1374 // so rotate the root back to where it was
1375 OdePrim parent = (OdePrim)_parent;
1376 parent.rotate(timestep);
1377 }
1378 else
1379 {
1380 //Just rotate the prim
1381 rotate(timestep);
1382 }
1383 }
1384 //
1385
1386 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent))
1387 changePhysicsStatus(timestep);
1388 //
1389
1390 if (!_size.ApproxEquals(m_taintsize,0f))
1391 changesize(timestep);
1392 //
1393
1394 if (m_taintshape)
1395 changeshape(timestep);
1396 //
1397
1398 if (m_taintforce)
1399 changeAddForce(timestep);
1400
1401 if (m_taintaddangularforce)
1402 changeAddAngularForce(timestep);
1403
1404 if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f))
1405 changeSetTorque(timestep);
1406
1407 if (m_taintdisable)
1408 changedisable(timestep);
1409
1410 if (m_taintselected != m_isSelected)
1411 changeSelectedStatus(timestep);
1412
1413 if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f))
1414 changevelocity(timestep);
1415
1416 if (m_taintparent != _parent)
1417 changelink(timestep);
1418
1419 if (m_taintCollidesWater != m_collidesWater)
1420 changefloatonwater(timestep);
1421/* obsolete
1422 if (!m_angularLock.ApproxEquals(m_taintAngularLock,0f))
1423 changeAngularLock(timestep);
1424 */
1425 }
1426 else
1427 {
1428 m_log.Error("[PHYSICS]: The scene reused a disposed PhysActor! *waves finger*, Don't be evil. A couple of things can cause this. An improper prim breakdown(be sure to set prim_geom to zero after d.GeomDestroy! An improper buildup (creating the geom failed). Or, the Scene Reused a physics actor after disposing it.)");
1429 }
1430 }
1431
1432/* obsolete
1433 private void changeAngularLock(float timestep)
1434 {
1435 if (_parent == null)
1436 {
1437 m_angularLock = m_taintAngularLock;
1438 m_angularLockSet = true;
1439 }
1440 }
1441 */
1442 private void changelink(float timestep)
1443 {
1444 // If the newly set parent is not null
1445 // create link
1446 if (_parent == null && m_taintparent != null)
1447 {
1448 if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim)
1449 {
1450 OdePrim obj = (OdePrim)m_taintparent;
1451 //obj.disableBody();
1452 obj.ParentPrim(this);
1453
1454 /*
1455 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
1456 {
1457 _linkJointGroup = d.JointGroupCreate(0);
1458 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1459 d.JointAttach(m_linkJoint, obj.Body, Body);
1460 d.JointSetFixed(m_linkJoint);
1461 }
1462 */
1463 }
1464 }
1465 // If the newly set parent is null
1466 // destroy link
1467 else if (_parent != null && m_taintparent == null)
1468 {
1469 if (_parent is OdePrim)
1470 {
1471 OdePrim obj = (OdePrim)_parent;
1472 obj.ChildDelink(this);
1473 childPrim = false;
1474 //_parent = null;
1475 }
1476
1477 /*
1478 if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0)
1479 d.JointGroupDestroy(_linkJointGroup);
1480
1481 _linkJointGroup = (IntPtr)0;
1482 m_linkJoint = (IntPtr)0;
1483 */
1484 }
1485
1486 _parent = m_taintparent;
1487 m_taintPhysics = m_isphysical;
1488 }
1489
1490 // I'm the parent
1491 // prim is the child
1492 public void ParentPrim(OdePrim prim)
1493 {
1494 if (this.m_localID != prim.m_localID)
1495 {
1496 if (Body == IntPtr.Zero)
1497 {
1498 Body = d.BodyCreate(_parent_scene.world);
1499 setMass();
1500 }
1501 if (Body != IntPtr.Zero)
1502 {
1503 lock (childrenPrim)
1504 {
1505 if (!childrenPrim.Contains(prim))
1506 {
1507 childrenPrim.Add(prim);
1508
1509 foreach (OdePrim prm in childrenPrim)
1510 {
1511 d.Mass m2;
1512 d.MassSetZero(out m2);
1513 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1514
1515
1516 d.Quaternion quat = new d.Quaternion();
1517 quat.W = prm._orientation.W;
1518 quat.X = prm._orientation.X;
1519 quat.Y = prm._orientation.Y;
1520 quat.Z = prm._orientation.Z;
1521
1522 d.Matrix3 mat = new d.Matrix3();
1523 d.RfromQ(out mat, ref quat);
1524 d.MassRotate(ref m2, ref mat);
1525 d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z);
1526 d.MassAdd(ref pMass, ref m2);
1527 }
1528 foreach (OdePrim prm in childrenPrim)
1529 {
1530
1531 prm.m_collisionCategories |= CollisionCategories.Body;
1532 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1533
1534 if (prm.prim_geom == IntPtr.Zero)
1535 {
1536 m_log.Warn("[PHYSICS]: Unable to link one of the linkset elements. No geom yet");
1537 continue;
1538 }
1539//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + m_primName);
1540 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1541 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1542
1543
1544 d.Quaternion quat = new d.Quaternion();
1545 quat.W = prm._orientation.W;
1546 quat.X = prm._orientation.X;
1547 quat.Y = prm._orientation.Y;
1548 quat.Z = prm._orientation.Z;
1549
1550 d.Matrix3 mat = new d.Matrix3();
1551 d.RfromQ(out mat, ref quat);
1552 if (Body != IntPtr.Zero)
1553 {
1554 d.GeomSetBody(prm.prim_geom, Body);
1555 prm.childPrim = true;
1556 d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z);
1557 //d.GeomSetOffsetPosition(prim.prim_geom,
1558 // (Position.X - prm.Position.X) - pMass.c.X,
1559 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1560 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1561 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat);
1562 //d.GeomSetOffsetRotation(prm.prim_geom, ref mat);
1563 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1564 d.BodySetMass(Body, ref pMass);
1565 }
1566 else
1567 {
1568 m_log.Debug("[PHYSICS]:I ain't got no boooooooooddy, no body");
1569 }
1570
1571
1572 prm.m_interpenetrationcount = 0;
1573 prm.m_collisionscore = 0;
1574 prm.m_disabled = false;
1575
1576 prm.Body = Body;
1577 _parent_scene.addActivePrim(prm);
1578 }
1579 m_collisionCategories |= CollisionCategories.Body;
1580 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1581
1582//Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + m_primName);
1583 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1584//Console.WriteLine(" Post GeomSetCategoryBits 2");
1585 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1586
1587
1588 d.Quaternion quat2 = new d.Quaternion();
1589 quat2.W = _orientation.W;
1590 quat2.X = _orientation.X;
1591 quat2.Y = _orientation.Y;
1592 quat2.Z = _orientation.Z;
1593
1594 d.Matrix3 mat2 = new d.Matrix3();
1595 d.RfromQ(out mat2, ref quat2);
1596 d.GeomSetBody(prim_geom, Body);
1597 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1598 //d.GeomSetOffsetPosition(prim.prim_geom,
1599 // (Position.X - prm.Position.X) - pMass.c.X,
1600 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1601 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1602 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1603 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1604 d.BodySetMass(Body, ref pMass);
1605
1606 d.BodySetAutoDisableFlag(Body, true);
1607 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1608
1609
1610 m_interpenetrationcount = 0;
1611 m_collisionscore = 0;
1612 m_disabled = false;
1613
1614 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1615 if (m_type != Vehicle.TYPE_NONE) Enable(Body, _parent_scene);
1616 _parent_scene.addActivePrim(this);
1617 }
1618 }
1619 }
1620 }
1621
1622 }
1623
1624 private void ChildSetGeom(OdePrim odePrim)
1625 {
1626 //if (m_isphysical && Body != IntPtr.Zero)
1627 lock (childrenPrim)
1628 {
1629 foreach (OdePrim prm in childrenPrim)
1630 {
1631 //prm.childPrim = true;
1632 prm.disableBody();
1633 //prm.m_taintparent = null;
1634 //prm._parent = null;
1635 //prm.m_taintPhysics = false;
1636 //prm.m_disabled = true;
1637 //prm.childPrim = false;
1638 }
1639 }
1640 disableBody();
1641
1642
1643 if (Body != IntPtr.Zero)
1644 {
1645 _parent_scene.remActivePrim(this);
1646 }
1647
1648 lock (childrenPrim)
1649 {
1650 foreach (OdePrim prm in childrenPrim)
1651 {
1652 ParentPrim(prm);
1653 }
1654 }
1655
1656 }
1657
1658 private void ChildDelink(OdePrim odePrim)
1659 {
1660 // Okay, we have a delinked child.. need to rebuild the body.
1661 lock (childrenPrim)
1662 {
1663 foreach (OdePrim prm in childrenPrim)
1664 {
1665 prm.childPrim = true;
1666 prm.disableBody();
1667 //prm.m_taintparent = null;
1668 //prm._parent = null;
1669 //prm.m_taintPhysics = false;
1670 //prm.m_disabled = true;
1671 //prm.childPrim = false;
1672 }
1673 }
1674 disableBody();
1675
1676 lock (childrenPrim)
1677 {
1678 childrenPrim.Remove(odePrim);
1679 }
1680
1681 if (Body != IntPtr.Zero)
1682 {
1683 _parent_scene.remActivePrim(this);
1684 }
1685
1686 lock (childrenPrim)
1687 {
1688 foreach (OdePrim prm in childrenPrim)
1689 {
1690 ParentPrim(prm);
1691 }
1692 }
1693 }
1694
1695 private void changeSelectedStatus(float timestep)
1696 {
1697 if (m_taintselected)
1698 {
1699 m_collisionCategories = CollisionCategories.Selected;
1700 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1701
1702 // We do the body disable soft twice because 'in theory' a collision could have happened
1703 // in between the disabling and the collision properties setting
1704 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1705 // through the ground.
1706
1707 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1708 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1709 // so that causes the selected part to wake up and continue moving.
1710
1711 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1712 // assembly will stop simulating during the selection, because of the lack of atomicity
1713 // of select operations (their processing could be interrupted by a thread switch, causing
1714 // simulation to continue before all of the selected object notifications trickle down to
1715 // the physics engine).
1716
1717 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1718 // selected and disabled. then, due to a thread switch, the selection processing is
1719 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1720 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1721 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1722 // up, start simulating again, which in turn wakes up the last 50.
1723
1724 if (m_isphysical)
1725 {
1726 disableBodySoft();
1727 }
1728
1729 if (prim_geom != IntPtr.Zero)
1730 {
1731 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1732 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1733 }
1734
1735 if (m_isphysical)
1736 {
1737 disableBodySoft();
1738
1739 if (Body != IntPtr.Zero)
1740 {
1741 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1742 d.BodySetForce(Body, 0, 0, 0);
1743 enableBodySoft();
1744 }
1745 }
1746 }
1747 else
1748 {
1749 m_collisionCategories = CollisionCategories.Geom;
1750
1751 if (m_isphysical)
1752 m_collisionCategories |= CollisionCategories.Body;
1753
1754 m_collisionFlags = m_default_collisionFlags;
1755
1756 if (m_collidesLand)
1757 m_collisionFlags |= CollisionCategories.Land;
1758 if (m_collidesWater)
1759 m_collisionFlags |= CollisionCategories.Water;
1760
1761 if (prim_geom != IntPtr.Zero)
1762 {
1763 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1764 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1765 }
1766/* Uhhh - stop the motion if the object is _selected_!!
1767 if (m_isphysical)
1768 {
1769 if (Body != IntPtr.Zero)
1770 {
1771 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1772 d.BodySetForce(Body, 0, 0, 0);
1773 enableBodySoft();
1774 }
1775 }
1776*/
1777 }
1778
1779 resetCollisionAccounting();
1780 m_isSelected = m_taintselected;
1781 }//end changeSelectedStatus
1782
1783 public void ResetTaints()
1784 {
1785 m_taintposition = _position;
1786 m_taintrot = _orientation;
1787 m_taintPhysics = m_isphysical;
1788 m_taintselected = m_isSelected;
1789 m_taintsize = _size;
1790 m_taintshape = false;
1791 m_taintforce = false;
1792 m_taintdisable = false;
1793 m_taintVelocity = Vector3.Zero;
1794 }
1795
1796 public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh)
1797 {
1798//Console.WriteLine("CreateGeom:");
1799 if (_mesh != null) // Special - make mesh
1800 {
1801 setMesh(_parent_scene, _mesh);
1802 }
1803 else // not a mesh
1804 {
1805 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) // special profile??
1806 {
1807 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) // Equi-size
1808 {
1809 if (((_size.X / 2f) > 0f)) // Has size
1810 {
1811 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1812 try
1813 {
1814//Console.WriteLine(" CreateGeom 1");
1815 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1816 }
1817 catch (AccessViolationException)
1818 {
1819 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1820 ode.dunlock(_parent_scene.world);
1821 return;
1822 }
1823 }
1824 else
1825 {
1826 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1827 try
1828 {
1829//Console.WriteLine(" CreateGeom 2");
1830 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1831 }
1832 catch (AccessViolationException)
1833 {
1834 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1835 ode.dunlock(_parent_scene.world);
1836 return;
1837 }
1838 }
1839 }
1840 else // not equi-size
1841 {
1842 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1843 try
1844 {
1845//Console.WriteLine(" CreateGeom 3");
1846 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1847 }
1848 catch (AccessViolationException)
1849 {
1850 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1851 ode.dunlock(_parent_scene.world);
1852 return;
1853 }
1854 }
1855 }
1856
1857 else // not special profile
1858 {
1859 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1860 try
1861 {
1862//Console.WriteLine(" CreateGeom 4");
1863 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1864 }
1865 catch (AccessViolationException)
1866 {
1867 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1868 ode.dunlock(_parent_scene.world);
1869 return;
1870 }
1871 }
1872 }
1873 }
1874
1875 public void changeadd(float timestep)
1876 {
1877 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1878 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1879
1880 if (targetspace == IntPtr.Zero)
1881 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1882
1883 m_targetSpace = targetspace;
1884
1885 if (_mesh == null)
1886 {
1887 if (_parent_scene.needsMeshing(_pbs))
1888 {
1889 // Don't need to re-enable body.. it's done in SetMesh
1890 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1891 // createmesh returns null when it's a shape that isn't a cube.
1892 // m_log.Debug(m_localID);
1893 }
1894 }
1895
1896
1897 lock (_parent_scene.OdeLock)
1898 {
1899//Console.WriteLine("changeadd 1");
1900 CreateGeom(m_targetSpace, _mesh);
1901
1902 if (prim_geom != IntPtr.Zero)
1903 {
1904 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1905 d.Quaternion myrot = new d.Quaternion();
1906 myrot.X = _orientation.X;
1907 myrot.Y = _orientation.Y;
1908 myrot.Z = _orientation.Z;
1909 myrot.W = _orientation.W;
1910 d.GeomSetQuaternion(prim_geom, ref myrot);
1911 }
1912
1913 if (m_isphysical && Body == IntPtr.Zero)
1914 {
1915 enableBody();
1916 }
1917 }
1918
1919 changeSelectedStatus(timestep);
1920
1921 m_taintadd = false;
1922 }
1923
1924 public void changemove(float timestep)
1925 {
1926//Console.WriteLine("changemove sing/root {0} to {1}", m_primName, _position );
1927 if (m_isphysical)
1928 {
1929//Console.WriteLine("phys {0} {1} {2}", m_disabled, m_taintremove, childPrim);
1930// if (!m_disabled && !m_taintremove && !childPrim) After one edit m_disabled is sometimes set, disabling further edits!
1931 if (!m_taintremove && !childPrim)
1932 {
1933 if (Body == IntPtr.Zero)
1934 enableBody();
1935 //Prim auto disable after 20 frames,
1936 //if you move it, re-enable the prim manually.
1937 if (_parent != null)
1938 {
1939 if (m_linkJoint != IntPtr.Zero)
1940 {
1941 d.JointDestroy(m_linkJoint);
1942 m_linkJoint = IntPtr.Zero;
1943 }
1944 }
1945 if (Body != IntPtr.Zero)
1946 {
1947 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1948
1949 if (_parent != null)
1950 {
1951 OdePrim odParent = (OdePrim)_parent;
1952 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1953 {
1954// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1955Console.WriteLine(" JointCreateFixed");
1956 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1957 d.JointAttach(m_linkJoint, Body, odParent.Body);
1958 d.JointSetFixed(m_linkJoint);
1959 }
1960 }
1961 d.BodyEnable(Body);
1962 if (m_type != Vehicle.TYPE_NONE)
1963 {
1964 Enable(Body, _parent_scene);
1965 }
1966 }
1967 else
1968 {
1969 m_log.Warn("[PHYSICS]: Body Still null after enableBody(). This is a crash scenario.");
1970 }
1971 }
1972 //else
1973 // {
1974 //m_log.Debug("[BUG]: race!");
1975 //}
1976 }
1977 else
1978 {
1979 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1980 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1981 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1982
1983 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1984 m_targetSpace = tempspace;
1985
1986 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1987 if (prim_geom != IntPtr.Zero)
1988 {
1989 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1990
1991 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1992 d.SpaceAdd(m_targetSpace, prim_geom);
1993 }
1994 }
1995
1996 changeSelectedStatus(timestep);
1997
1998 resetCollisionAccounting();
1999 m_taintposition = _position;
2000 }
2001
2002
2003
2004 public void rotate(float timestep)
2005 {
2006 d.Quaternion myrot = new d.Quaternion();
2007 myrot.X = _orientation.X;
2008 myrot.Y = _orientation.Y;
2009 myrot.Z = _orientation.Z;
2010 myrot.W = _orientation.W;
2011 if (Body != IntPtr.Zero)
2012 {
2013 // KF: If this is a root prim do BodySet
2014 d.BodySetQuaternion(Body, ref myrot);
2015 }
2016 else
2017 {
2018 // daughter prim, do Geom set
2019 d.GeomSetQuaternion(prim_geom, ref myrot);
2020 }
2021
2022 resetCollisionAccounting();
2023 m_taintrot = _orientation;
2024 }
2025
2026 private void resetCollisionAccounting()
2027 {
2028 m_collisionscore = 0;
2029 m_interpenetrationcount = 0;
2030 m_disabled = false;
2031 }
2032
2033 public void changedisable(float timestep)
2034 {
2035 m_disabled = true;
2036 if (Body != IntPtr.Zero)
2037 {
2038 d.BodyDisable(Body);
2039 Body = IntPtr.Zero;
2040 }
2041
2042 m_taintdisable = false;
2043 }
2044
2045 public void changePhysicsStatus(float timestep)
2046 {
2047 if (m_isphysical == true)
2048 {
2049 if (Body == IntPtr.Zero)
2050 {
2051 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2052 {
2053 changeshape(2f);
2054 }
2055 else
2056 {
2057 enableBody();
2058 }
2059 }
2060 }
2061 else
2062 {
2063 if (Body != IntPtr.Zero)
2064 {
2065 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2066 {
2067 _mesh = null;
2068//Console.WriteLine("changePhysicsStatus for " + m_primName );
2069 changeadd(2f);
2070 }
2071 if (childPrim)
2072 {
2073 if (_parent != null)
2074 {
2075 OdePrim parent = (OdePrim)_parent;
2076 parent.ChildDelink(this);
2077 }
2078 }
2079 else
2080 {
2081 disableBody();
2082 }
2083 }
2084 }
2085
2086 changeSelectedStatus(timestep);
2087
2088 resetCollisionAccounting();
2089 m_taintPhysics = m_isphysical;
2090 }
2091
2092 public void changesize(float timestamp)
2093 {
2094
2095 string oldname = _parent_scene.geom_name_map[prim_geom];
2096
2097 if (_size.X <= 0) _size.X = 0.01f;
2098 if (_size.Y <= 0) _size.Y = 0.01f;
2099 if (_size.Z <= 0) _size.Z = 0.01f;
2100
2101 // Cleanup of old prim geometry
2102 if (_mesh != null)
2103 {
2104 // Cleanup meshing here
2105 }
2106 //kill body to rebuild
2107 if (IsPhysical && Body != IntPtr.Zero)
2108 {
2109 if (childPrim)
2110 {
2111 if (_parent != null)
2112 {
2113 OdePrim parent = (OdePrim)_parent;
2114 parent.ChildDelink(this);
2115 }
2116 }
2117 else
2118 {
2119 disableBody();
2120 }
2121 }
2122 if (d.SpaceQuery(m_targetSpace, prim_geom))
2123 {
2124 _parent_scene.waitForSpaceUnlock(m_targetSpace);
2125 d.SpaceRemove(m_targetSpace, prim_geom);
2126 }
2127 // we don't need to do space calculation because the client sends a position update also.
2128
2129 // Construction of new prim
2130 if (_parent_scene.needsMeshing(_pbs))
2131 {
2132 float meshlod = _parent_scene.meshSculptLOD;
2133
2134 if (IsPhysical)
2135 meshlod = _parent_scene.MeshSculptphysicalLOD;
2136 // Don't need to re-enable body.. it's done in SetMesh
2137
2138 IMesh mesh = null;
2139
2140 if (_parent_scene.needsMeshing(_pbs))
2141 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2142
2143 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2144//Console.WriteLine("changesize 1");
2145 CreateGeom(m_targetSpace, mesh);
2146
2147
2148 }
2149 else
2150 {
2151 _mesh = null;
2152//Console.WriteLine("changesize 2");
2153 CreateGeom(m_targetSpace, _mesh);
2154 }
2155
2156 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2157 d.Quaternion myrot = new d.Quaternion();
2158 myrot.X = _orientation.X;
2159 myrot.Y = _orientation.Y;
2160 myrot.Z = _orientation.Z;
2161 myrot.W = _orientation.W;
2162 d.GeomSetQuaternion(prim_geom, ref myrot);
2163
2164 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2165 if (IsPhysical && Body == IntPtr.Zero && !childPrim)
2166 {
2167 // Re creates body on size.
2168 // EnableBody also does setMass()
2169 enableBody();
2170 d.BodyEnable(Body);
2171 }
2172
2173 _parent_scene.geom_name_map[prim_geom] = oldname;
2174
2175 changeSelectedStatus(timestamp);
2176 if (childPrim)
2177 {
2178 if (_parent is OdePrim)
2179 {
2180 OdePrim parent = (OdePrim)_parent;
2181 parent.ChildSetGeom(this);
2182 }
2183 }
2184 resetCollisionAccounting();
2185 m_taintsize = _size;
2186 }
2187
2188
2189
2190 public void changefloatonwater(float timestep)
2191 {
2192 m_collidesWater = m_taintCollidesWater;
2193
2194 if (prim_geom != IntPtr.Zero)
2195 {
2196 if (m_collidesWater)
2197 {
2198 m_collisionFlags |= CollisionCategories.Water;
2199 }
2200 else
2201 {
2202 m_collisionFlags &= ~CollisionCategories.Water;
2203 }
2204 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2205 }
2206 }
2207
2208 public void changeshape(float timestamp)
2209 {
2210 string oldname = _parent_scene.geom_name_map[prim_geom];
2211
2212 // Cleanup of old prim geometry and Bodies
2213 if (IsPhysical && Body != IntPtr.Zero)
2214 {
2215 if (childPrim)
2216 {
2217 if (_parent != null)
2218 {
2219 OdePrim parent = (OdePrim)_parent;
2220 parent.ChildDelink(this);
2221 }
2222 }
2223 else
2224 {
2225 disableBody();
2226 }
2227 }
2228
2229
2230 // we don't need to do space calculation because the client sends a position update also.
2231 if (_size.X <= 0) _size.X = 0.01f;
2232 if (_size.Y <= 0) _size.Y = 0.01f;
2233 if (_size.Z <= 0) _size.Z = 0.01f;
2234 // Construction of new prim
2235
2236 if (_parent_scene.needsMeshing(_pbs))
2237 {
2238 // Don't need to re-enable body.. it's done in SetMesh
2239 float meshlod = _parent_scene.meshSculptLOD;
2240
2241 if (IsPhysical)
2242 meshlod = _parent_scene.MeshSculptphysicalLOD;
2243
2244 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2245 // createmesh returns null when it doesn't mesh.
2246 CreateGeom(m_targetSpace, mesh);
2247 }
2248 else
2249 {
2250 _mesh = null;
2251//Console.WriteLine("changeshape");
2252 CreateGeom(m_targetSpace, null);
2253 }
2254
2255 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2256 d.Quaternion myrot = new d.Quaternion();
2257 //myrot.W = _orientation.w;
2258 myrot.W = _orientation.W;
2259 myrot.X = _orientation.X;
2260 myrot.Y = _orientation.Y;
2261 myrot.Z = _orientation.Z;
2262 d.GeomSetQuaternion(prim_geom, ref myrot);
2263
2264 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2265 if (IsPhysical && Body == IntPtr.Zero)
2266 {
2267 // Re creates body on size.
2268 // EnableBody also does setMass()
2269 enableBody();
2270 if (Body != IntPtr.Zero)
2271 {
2272 d.BodyEnable(Body);
2273 }
2274 }
2275 _parent_scene.geom_name_map[prim_geom] = oldname;
2276
2277 changeSelectedStatus(timestamp);
2278 if (childPrim)
2279 {
2280 if (_parent is OdePrim)
2281 {
2282 OdePrim parent = (OdePrim)_parent;
2283 parent.ChildSetGeom(this);
2284 }
2285 }
2286 resetCollisionAccounting();
2287 m_taintshape = false;
2288 }
2289
2290 public void changeAddForce(float timestamp)
2291 {
2292 if (!m_isSelected)
2293 {
2294 lock (m_forcelist)
2295 {
2296 //m_log.Info("[PHYSICS]: dequeing forcelist");
2297 if (IsPhysical)
2298 {
2299 Vector3 iforce = Vector3.Zero;
2300 int i = 0;
2301 try
2302 {
2303 for (i = 0; i < m_forcelist.Count; i++)
2304 {
2305
2306 iforce = iforce + (m_forcelist[i] * 100);
2307 }
2308 }
2309 catch (IndexOutOfRangeException)
2310 {
2311 m_forcelist = new List<Vector3>();
2312 m_collisionscore = 0;
2313 m_interpenetrationcount = 0;
2314 m_taintforce = false;
2315 return;
2316 }
2317 catch (ArgumentOutOfRangeException)
2318 {
2319 m_forcelist = new List<Vector3>();
2320 m_collisionscore = 0;
2321 m_interpenetrationcount = 0;
2322 m_taintforce = false;
2323 return;
2324 }
2325 d.BodyEnable(Body);
2326 d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
2327 }
2328 m_forcelist.Clear();
2329 }
2330
2331 m_collisionscore = 0;
2332 m_interpenetrationcount = 0;
2333 }
2334
2335 m_taintforce = false;
2336
2337 }
2338
2339
2340
2341 public void changeSetTorque(float timestamp)
2342 {
2343 if (!m_isSelected)
2344 {
2345 if (IsPhysical && Body != IntPtr.Zero)
2346 {
2347 d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z);
2348 }
2349 }
2350
2351 m_taintTorque = Vector3.Zero;
2352 }
2353
2354 public void changeAddAngularForce(float timestamp)
2355 {
2356 if (!m_isSelected)
2357 {
2358 lock (m_angularforcelist)
2359 {
2360 //m_log.Info("[PHYSICS]: dequeing forcelist");
2361 if (IsPhysical)
2362 {
2363 Vector3 iforce = Vector3.Zero;
2364 for (int i = 0; i < m_angularforcelist.Count; i++)
2365 {
2366 iforce = iforce + (m_angularforcelist[i] * 100);
2367 }
2368 d.BodyEnable(Body);
2369 d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z);
2370
2371 }
2372 m_angularforcelist.Clear();
2373 }
2374
2375 m_collisionscore = 0;
2376 m_interpenetrationcount = 0;
2377 }
2378
2379 m_taintaddangularforce = false;
2380 }
2381
2382 private void changevelocity(float timestep)
2383 {
2384 if (!m_isSelected)
2385 {
2386 Thread.Sleep(20);
2387 if (IsPhysical)
2388 {
2389 if (Body != IntPtr.Zero)
2390 d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
2391 }
2392
2393 //resetCollisionAccounting();
2394 }
2395 m_taintVelocity = Vector3.Zero;
2396 }
2397
2398 public void UpdatePositionAndVelocity()
2399 {
2400 return; // moved to the Move () method
2401 }
2402
2403 public d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj)
2404 {
2405 obj.I.M00 = pMat[0, 0];
2406 obj.I.M01 = pMat[0, 1];
2407 obj.I.M02 = pMat[0, 2];
2408 obj.I.M10 = pMat[1, 0];
2409 obj.I.M11 = pMat[1, 1];
2410 obj.I.M12 = pMat[1, 2];
2411 obj.I.M20 = pMat[2, 0];
2412 obj.I.M21 = pMat[2, 1];
2413 obj.I.M22 = pMat[2, 2];
2414 return obj;
2415 }
2416
2417 public override void SubscribeEvents(int ms)
2418 {
2419 m_eventsubscription = ms;
2420 _parent_scene.addCollisionEventReporting(this);
2421 }
2422
2423 public override void UnSubscribeEvents()
2424 {
2425 _parent_scene.remCollisionEventReporting(this);
2426 m_eventsubscription = 0;
2427 }
2428
2429 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
2430 {
2431 if (CollisionEventsThisFrame == null)
2432 CollisionEventsThisFrame = new CollisionEventUpdate();
2433 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
2434 }
2435
2436 public void SendCollisions()
2437 {
2438 if (CollisionEventsThisFrame == null)
2439 return;
2440
2441 base.SendCollisionUpdate(CollisionEventsThisFrame);
2442
2443 if (CollisionEventsThisFrame.m_objCollisionList.Count == 0)
2444 CollisionEventsThisFrame = null;
2445 else
2446 CollisionEventsThisFrame = new CollisionEventUpdate();
2447 }
2448
2449 public override bool SubscribedEvents()
2450 {
2451 if (m_eventsubscription > 0)
2452 return true;
2453 return false;
2454 }
2455
2456 public static Matrix4 Inverse(Matrix4 pMat)
2457 {
2458 if (determinant3x3(pMat) == 0)
2459 {
2460 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
2461 }
2462
2463
2464
2465 return (Adjoint(pMat) / determinant3x3(pMat));
2466 }
2467
2468 public static Matrix4 Adjoint(Matrix4 pMat)
2469 {
2470 Matrix4 adjointMatrix = new Matrix4();
2471 for (int i=0; i<4; i++)
2472 {
2473 for (int j=0; j<4; j++)
2474 {
2475 Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j)))));
2476 }
2477 }
2478
2479 adjointMatrix = Transpose(adjointMatrix);
2480 return adjointMatrix;
2481 }
2482
2483 public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol)
2484 {
2485 Matrix4 minor = new Matrix4();
2486 int m = 0, n = 0;
2487 for (int i = 0; i < 4; i++)
2488 {
2489 if (i == iRow)
2490 continue;
2491 n = 0;
2492 for (int j = 0; j < 4; j++)
2493 {
2494 if (j == iCol)
2495 continue;
2496 Matrix4SetValue(ref minor, m,n, matrix[i, j]);
2497 n++;
2498 }
2499 m++;
2500 }
2501 return minor;
2502 }
2503
2504 public static Matrix4 Transpose(Matrix4 pMat)
2505 {
2506 Matrix4 transposeMatrix = new Matrix4();
2507 for (int i = 0; i < 4; i++)
2508 for (int j = 0; j < 4; j++)
2509 Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]);
2510 return transposeMatrix;
2511 }
2512
2513 public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val)
2514 {
2515 switch (r)
2516 {
2517 case 0:
2518 switch (c)
2519 {
2520 case 0:
2521 pMat.M11 = val;
2522 break;
2523 case 1:
2524 pMat.M12 = val;
2525 break;
2526 case 2:
2527 pMat.M13 = val;
2528 break;
2529 case 3:
2530 pMat.M14 = val;
2531 break;
2532 }
2533
2534 break;
2535 case 1:
2536 switch (c)
2537 {
2538 case 0:
2539 pMat.M21 = val;
2540 break;
2541 case 1:
2542 pMat.M22 = val;
2543 break;
2544 case 2:
2545 pMat.M23 = val;
2546 break;
2547 case 3:
2548 pMat.M24 = val;
2549 break;
2550 }
2551
2552 break;
2553 case 2:
2554 switch (c)
2555 {
2556 case 0:
2557 pMat.M31 = val;
2558 break;
2559 case 1:
2560 pMat.M32 = val;
2561 break;
2562 case 2:
2563 pMat.M33 = val;
2564 break;
2565 case 3:
2566 pMat.M34 = val;
2567 break;
2568 }
2569
2570 break;
2571 case 3:
2572 switch (c)
2573 {
2574 case 0:
2575 pMat.M41 = val;
2576 break;
2577 case 1:
2578 pMat.M42 = val;
2579 break;
2580 case 2:
2581 pMat.M43 = val;
2582 break;
2583 case 3:
2584 pMat.M44 = val;
2585 break;
2586 }
2587
2588 break;
2589 }
2590 }
2591 private static float determinant3x3(Matrix4 pMat)
2592 {
2593 float det = 0;
2594 float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2];
2595 float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0];
2596 float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1];
2597 float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2];
2598 float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0];
2599 float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1];
2600
2601 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
2602 return det;
2603
2604 }
2605
2606 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
2607 {
2608 dst.c.W = src.c.W;
2609 dst.c.X = src.c.X;
2610 dst.c.Y = src.c.Y;
2611 dst.c.Z = src.c.Z;
2612 dst.mass = src.mass;
2613 dst.I.M00 = src.I.M00;
2614 dst.I.M01 = src.I.M01;
2615 dst.I.M02 = src.I.M02;
2616 dst.I.M10 = src.I.M10;
2617 dst.I.M11 = src.I.M11;
2618 dst.I.M12 = src.I.M12;
2619 dst.I.M20 = src.I.M20;
2620 dst.I.M21 = src.I.M21;
2621 dst.I.M22 = src.I.M22;
2622 }
2623
2624 public override void SetMaterial(int pMaterial)
2625 {
2626 m_material = pMaterial;
2627 }
2628
2629 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
2630 {
2631 switch (pParam)
2632 {
2633 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
2634 if (pValue < 0.01f) pValue = 0.01f;
2635 // m_angularDeflectionEfficiency = pValue;
2636 break;
2637 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
2638 if (pValue < 0.1f) pValue = 0.1f;
2639 // m_angularDeflectionTimescale = pValue;
2640 break;
2641 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
2642 if (pValue < 0.3f) pValue = 0.3f;
2643 m_angularMotorDecayTimescale = pValue;
2644 break;
2645 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
2646 if (pValue < 0.3f) pValue = 0.3f;
2647 m_angularMotorTimescale = pValue;
2648 break;
2649 case Vehicle.BANKING_EFFICIENCY:
2650 if (pValue < 0.01f) pValue = 0.01f;
2651 // m_bankingEfficiency = pValue;
2652 break;
2653 case Vehicle.BANKING_MIX:
2654 if (pValue < 0.01f) pValue = 0.01f;
2655 // m_bankingMix = pValue;
2656 break;
2657 case Vehicle.BANKING_TIMESCALE:
2658 if (pValue < 0.01f) pValue = 0.01f;
2659 // m_bankingTimescale = pValue;
2660 break;
2661 case Vehicle.BUOYANCY:
2662 if (pValue < -1f) pValue = -1f;
2663 if (pValue > 1f) pValue = 1f;
2664 m_VehicleBuoyancy = pValue;
2665 break;
2666// case Vehicle.HOVER_EFFICIENCY:
2667// if (pValue < 0f) pValue = 0f;
2668// if (pValue > 1f) pValue = 1f;
2669// m_VhoverEfficiency = pValue;
2670// break;
2671 case Vehicle.HOVER_HEIGHT:
2672 m_VhoverHeight = pValue;
2673 break;
2674 case Vehicle.HOVER_TIMESCALE:
2675 if (pValue < 0.1f) pValue = 0.1f;
2676 m_VhoverTimescale = pValue;
2677 break;
2678 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
2679 if (pValue < 0.01f) pValue = 0.01f;
2680 // m_linearDeflectionEfficiency = pValue;
2681 break;
2682 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
2683 if (pValue < 0.01f) pValue = 0.01f;
2684 // m_linearDeflectionTimescale = pValue;
2685 break;
2686 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
2687 if (pValue < 0.3f) pValue = 0.3f;
2688 m_linearMotorDecayTimescale = pValue;
2689 break;
2690 case Vehicle.LINEAR_MOTOR_TIMESCALE:
2691 if (pValue < 0.1f) pValue = 0.1f;
2692 m_linearMotorTimescale = pValue;
2693 break;
2694 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
2695 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
2696 if (pValue > 1.0f) pValue = 1.0f;
2697 m_verticalAttractionEfficiency = pValue;
2698 break;
2699 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
2700 if (pValue < 0.1f) pValue = 0.1f;
2701 m_verticalAttractionTimescale = pValue;
2702 break;
2703
2704 // These are vector properties but the engine lets you use a single float value to
2705 // set all of the components to the same value
2706 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2707 if (pValue > 30f) pValue = 30f;
2708 if (pValue < 0.1f) pValue = 0.1f;
2709 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
2710 break;
2711 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2712 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
2713 UpdateAngDecay();
2714 break;
2715 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2716 if (pValue < 0.1f) pValue = 0.1f;
2717 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
2718 break;
2719 case Vehicle.LINEAR_MOTOR_DIRECTION:
2720 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
2721 UpdateLinDecay();
2722 break;
2723 case Vehicle.LINEAR_MOTOR_OFFSET:
2724 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
2725 break;
2726
2727 }
2728
2729 }//end ProcessFloatVehicleParam
2730
2731 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
2732 {
2733 switch (pParam)
2734 {
2735 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2736 if (pValue.X > 30f) pValue.X = 30f;
2737 if (pValue.X < 0.1f) pValue.X = 0.1f;
2738 if (pValue.Y > 30f) pValue.Y = 30f;
2739 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2740 if (pValue.Z > 30f) pValue.Z = 30f;
2741 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2742 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2743 break;
2744 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2745 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
2746 // Limit requested angular speed to 2 rps= 4 pi rads/sec
2747 if(m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
2748 if(m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
2749 if(m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
2750 if(m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
2751 if(m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
2752 if(m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
2753 UpdateAngDecay();
2754 break;
2755 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2756 if (pValue.X < 0.1f) pValue.X = 0.1f;
2757 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2758 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2759 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2760 break;
2761 case Vehicle.LINEAR_MOTOR_DIRECTION:
2762 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting
2763 UpdateLinDecay();
2764 break;
2765 case Vehicle.LINEAR_MOTOR_OFFSET:
2766 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
2767 break;
2768 }
2769
2770 }//end ProcessVectorVehicleParam
2771
2772 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
2773 {
2774 switch (pParam)
2775 {
2776 case Vehicle.REFERENCE_FRAME:
2777 // m_referenceFrame = pValue;
2778 break;
2779 }
2780
2781 }//end ProcessRotationVehicleParam
2782
2783 internal void ProcessVehicleFlags(int pParam, bool remove)
2784 {
2785 if (remove)
2786 {
2787 m_flags &= ~((VehicleFlag)pParam);
2788 }
2789 else
2790 {
2791 m_flags |= (VehicleFlag)pParam;
2792 }
2793 }
2794
2795 internal void ProcessTypeChange(Vehicle pType)
2796 {
2797 // Set Defaults For Type
2798 m_type = pType;
2799 switch (pType)
2800 {
2801 case Vehicle.TYPE_SLED:
2802 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
2803 m_angularFrictionTimescale = new Vector3(30, 30, 30);
2804// m_lLinMotorVel = Vector3.Zero;
2805 m_linearMotorTimescale = 1000;
2806 m_linearMotorDecayTimescale = 120;
2807 m_angularMotorDirection = Vector3.Zero;
2808 m_angularMotorDVel = Vector3.Zero;
2809 m_angularMotorTimescale = 1000;
2810 m_angularMotorDecayTimescale = 120;
2811 m_VhoverHeight = 0;
2812// m_VhoverEfficiency = 1;
2813 m_VhoverTimescale = 10;
2814 m_VehicleBuoyancy = 0;
2815 // m_linearDeflectionEfficiency = 1;
2816 // m_linearDeflectionTimescale = 1;
2817 // m_angularDeflectionEfficiency = 1;
2818 // m_angularDeflectionTimescale = 1000;
2819 // m_bankingEfficiency = 0;
2820 // m_bankingMix = 1;
2821 // m_bankingTimescale = 10;
2822 // m_referenceFrame = Quaternion.Identity;
2823 m_flags &=
2824 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2825 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2826 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2827 break;
2828 case Vehicle.TYPE_CAR:
2829 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
2830 m_angularFrictionTimescale = new Vector3(30, 30, 30); // was 1000, but sl max frict time is 30.
2831// m_lLinMotorVel = Vector3.Zero;
2832 m_linearMotorTimescale = 1;
2833 m_linearMotorDecayTimescale = 60;
2834 m_angularMotorDirection = Vector3.Zero;
2835 m_angularMotorDVel = Vector3.Zero;
2836 m_angularMotorTimescale = 1;
2837 m_angularMotorDecayTimescale = 0.8f;
2838 m_VhoverHeight = 0;
2839// m_VhoverEfficiency = 0;
2840 m_VhoverTimescale = 1000;
2841 m_VehicleBuoyancy = 0;
2842 // // m_linearDeflectionEfficiency = 1;
2843 // // m_linearDeflectionTimescale = 2;
2844 // // m_angularDeflectionEfficiency = 0;
2845 // m_angularDeflectionTimescale = 10;
2846 m_verticalAttractionEfficiency = 1f;
2847 m_verticalAttractionTimescale = 10f;
2848 // m_bankingEfficiency = -0.2f;
2849 // m_bankingMix = 1;
2850 // m_bankingTimescale = 1;
2851 // m_referenceFrame = Quaternion.Identity;
2852 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2853 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY |
2854 VehicleFlag.LIMIT_MOTOR_UP);
2855 break;
2856 case Vehicle.TYPE_BOAT:
2857 m_linearFrictionTimescale = new Vector3(10, 3, 2);
2858 m_angularFrictionTimescale = new Vector3(10,10,10);
2859// m_lLinMotorVel = Vector3.Zero;
2860 m_linearMotorTimescale = 5;
2861 m_linearMotorDecayTimescale = 60;
2862 m_angularMotorDirection = Vector3.Zero;
2863 m_angularMotorDVel = Vector3.Zero;
2864 m_angularMotorTimescale = 4;
2865 m_angularMotorDecayTimescale = 4;
2866 m_VhoverHeight = 0;
2867// m_VhoverEfficiency = 0.5f;
2868 m_VhoverTimescale = 2;
2869 m_VehicleBuoyancy = 1;
2870 // m_linearDeflectionEfficiency = 0.5f;
2871 // m_linearDeflectionTimescale = 3;
2872 // m_angularDeflectionEfficiency = 0.5f;
2873 // m_angularDeflectionTimescale = 5;
2874 m_verticalAttractionEfficiency = 0.5f;
2875 m_verticalAttractionTimescale = 5f;
2876 // m_bankingEfficiency = -0.3f;
2877 // m_bankingMix = 0.8f;
2878 // m_bankingTimescale = 1;
2879 // m_referenceFrame = Quaternion.Identity;
2880 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY |
2881 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2882 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY |
2883 VehicleFlag.LIMIT_MOTOR_UP);
2884 break;
2885 case Vehicle.TYPE_AIRPLANE:
2886 m_linearFrictionTimescale = new Vector3(200, 10, 5);
2887 m_angularFrictionTimescale = new Vector3(20, 20, 20);
2888// m_lLinMotorVel = Vector3.Zero;
2889 m_linearMotorTimescale = 2;
2890 m_linearMotorDecayTimescale = 60;
2891 m_angularMotorDirection = Vector3.Zero;
2892 m_angularMotorDVel = Vector3.Zero;
2893 m_angularMotorTimescale = 4;
2894 m_angularMotorDecayTimescale = 4;
2895 m_VhoverHeight = 0;
2896// m_VhoverEfficiency = 0.5f;
2897 m_VhoverTimescale = 1000;
2898 m_VehicleBuoyancy = 0;
2899 // m_linearDeflectionEfficiency = 0.5f;
2900 // m_linearDeflectionTimescale = 3;
2901 // m_angularDeflectionEfficiency = 1;
2902 // m_angularDeflectionTimescale = 2;
2903 m_verticalAttractionEfficiency = 0.9f;
2904 m_verticalAttractionTimescale = 2f;
2905 // m_bankingEfficiency = 1;
2906 // m_bankingMix = 0.7f;
2907 // m_bankingTimescale = 2;
2908 // m_referenceFrame = Quaternion.Identity;
2909 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2910 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2911 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
2912 break;
2913 case Vehicle.TYPE_BALLOON:
2914 m_linearFrictionTimescale = new Vector3(5, 5, 5);
2915 m_angularFrictionTimescale = new Vector3(10, 10, 10);
2916 m_linearMotorTimescale = 5;
2917 m_linearMotorDecayTimescale = 60;
2918 m_angularMotorDirection = Vector3.Zero;
2919 m_angularMotorDVel = Vector3.Zero;
2920 m_angularMotorTimescale = 6;
2921 m_angularMotorDecayTimescale = 10;
2922 m_VhoverHeight = 5;
2923// m_VhoverEfficiency = 0.8f;
2924 m_VhoverTimescale = 10;
2925 m_VehicleBuoyancy = 1;
2926 // m_linearDeflectionEfficiency = 0;
2927 // m_linearDeflectionTimescale = 5;
2928 // m_angularDeflectionEfficiency = 0;
2929 // m_angularDeflectionTimescale = 5;
2930 m_verticalAttractionEfficiency = 1f;
2931 m_verticalAttractionTimescale = 100f;
2932 // m_bankingEfficiency = 0;
2933 // m_bankingMix = 0.7f;
2934 // m_bankingTimescale = 5;
2935 // m_referenceFrame = Quaternion.Identity;
2936 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2937 VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2938 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2939 break;
2940
2941 }
2942 }//end SetDefaultsForType
2943
2944 internal void Enable(IntPtr pBody, OdeScene pParentScene)
2945 {
2946 if (m_type == Vehicle.TYPE_NONE)
2947 return;
2948
2949 m_body = pBody;
2950 }
2951
2952
2953 internal void Halt()
2954 { // Kill all motions, when non-physical
2955 // m_linearMotorDirection = Vector3.Zero;
2956 m_lLinMotorDVel = Vector3.Zero;
2957 m_lLinObjectVel = Vector3.Zero;
2958 m_wLinObjectVel = Vector3.Zero;
2959 m_angularMotorDirection = Vector3.Zero;
2960 m_lastAngularVelocity = Vector3.Zero;
2961 m_angularMotorDVel = Vector3.Zero;
2962 _acceleration = Vector3.Zero;
2963 }
2964
2965 private void UpdateLinDecay()
2966 {
2967// if (Math.Abs(m_linearMotorDirection.X) > Math.Abs(m_lLinMotorDVel.X)) m_lLinMotorDVel.X = m_linearMotorDirection.X;
2968// if (Math.Abs(m_linearMotorDirection.Y) > Math.Abs(m_lLinMotorDVel.Y)) m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2969// if (Math.Abs(m_linearMotorDirection.Z) > Math.Abs(m_lLinMotorDVel.Z)) m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2970 m_lLinMotorDVel.X = m_linearMotorDirection.X;
2971 m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2972 m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2973 } // else let the motor decay on its own
2974
2975 private void UpdateAngDecay()
2976 {
2977// if (Math.Abs(m_angularMotorDirection.X) > Math.Abs(m_angularMotorDVel.X)) m_angularMotorDVel.X = m_angularMotorDirection.X;
2978// if (Math.Abs(m_angularMotorDirection.Y) > Math.Abs(m_angularMotorDVel.Y)) m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2979// if (Math.Abs(m_angularMotorDirection.Z) > Math.Abs(m_angularMotorDVel.Z)) m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2980 m_angularMotorDVel.X = m_angularMotorDirection.X;
2981 m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2982 m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2983 } // else let the motor decay on its own
2984
2985 public void Move(float timestep)
2986 {
2987 float fx = 0;
2988 float fy = 0;
2989 float fz = 0;
2990 Vector3 linvel; // velocity applied, including any reversal
2991 int outside = 0;
2992
2993 // If geomCrossingFailuresBeforeOutofbounds is set to 0 in OpenSim.ini then phys objects bounce off region borders.
2994 // This is a temp patch until proper region crossing is developed.
2995
2996 int failureLimit = _parent_scene.geomCrossingFailuresBeforeOutofbounds;
2997 int fence = _parent_scene.geomRegionFence;
2998
2999 float border_limit = 0.05f; // original limit
3000 if (fence == 1) border_limit = 0.5f; // bounce point
3001
3002 frcount++; // used to limit debug comment output
3003 if (frcount > 50)
3004 frcount = 0;
3005
3006 if(revcount > 0) revcount--;
3007
3008 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // Only move root prims.
3009 {
3010 // Old public void UpdatePositionAndVelocity(), more accuratley calculated here
3011 bool lastZeroFlag = _zeroFlag; // was it stopped
3012
3013 d.Vector3 vec = d.BodyGetPosition(Body);
3014 Vector3 l_position = Vector3.Zero;
3015 l_position.X = vec.X;
3016 l_position.Y = vec.Y;
3017 l_position.Z = vec.Z;
3018 m_lastposition = _position;
3019 _position = l_position;
3020
3021 d.Quaternion ori = d.BodyGetQuaternion(Body);
3022 // Quaternion l_orientation = Quaternion.Identity;
3023 _orientation.X = ori.X;
3024 _orientation.Y = ori.Y;
3025 _orientation.Z = ori.Z;
3026 _orientation.W = ori.W;
3027 m_lastorientation = _orientation;
3028
3029 d.Vector3 vel = d.BodyGetLinearVel(Body);
3030 m_lastVelocity = _velocity;
3031 _velocity.X = vel.X;
3032 _velocity.Y = vel.Y;
3033 _velocity.Z = vel.Z;
3034 _acceleration = ((_velocity - m_lastVelocity) / timestep);
3035
3036 d.Vector3 torque = d.BodyGetTorque(Body);
3037 _torque = new Vector3(torque.X, torque.Y, torque.Z);
3038
3039 base.RequestPhysicsterseUpdate();
3040
3041//Console.WriteLine("Move {0} at {1}", m_primName, l_position);
3042
3043 // Check if outside region
3044 // In Scene.cs/CrossPrimGroupIntoNewRegion the object is checked for 0.1M from border!
3045 if (l_position.X > ((float)_parent_scene.WorldExtents.X - border_limit))
3046 {
3047 l_position.X = ((float)_parent_scene.WorldExtents.X - border_limit);
3048 outside = 1;
3049 }
3050
3051 if (l_position.X < border_limit)
3052 {
3053 l_position.X = border_limit;
3054 outside = 2;
3055 }
3056 if (l_position.Y > ((float)_parent_scene.WorldExtents.Y - border_limit))
3057 {
3058 l_position.Y = ((float)_parent_scene.WorldExtents.Y - border_limit);
3059 outside = 3;
3060 }
3061
3062 if (l_position.Y < border_limit)
3063 {
3064 l_position.Y = border_limit;
3065 outside = 4;
3066 }
3067
3068 if (outside > 0)
3069 {
3070//Console.WriteLine(" fence = {0}",fence);
3071
3072//Console.WriteLine("Border {0}", l_position);
3073 if (fence == 1) // bounce object off boundary
3074 {
3075 if (revcount == 0)
3076 {
3077 if (outside < 3)
3078 {
3079 _velocity.X = -_velocity.X;
3080 }
3081 else
3082 {
3083 _velocity.Y = -_velocity.Y;
3084 }
3085 if (m_type != Vehicle.TYPE_NONE) Halt();
3086 _position = l_position;
3087 m_taintposition = _position;
3088 m_lastVelocity = _velocity;
3089 _acceleration = Vector3.Zero;
3090 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
3091 d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
3092 base.RequestPhysicsterseUpdate();
3093
3094 revcount = 25; // wait for object to move away from border
3095 }
3096 } // else old crossing mode
3097 else if (m_crossingfailures < failureLimit)
3098 { // keep trying to cross?
3099 _position = l_position;
3100 //_parent_scene.remActivePrim(this);
3101 if (_parent == null) base.RequestPhysicsterseUpdate();
3102 return; // Dont process any other motion?
3103 }
3104 else
3105 { // Too many tries
3106 if (_parent == null) base.RaiseOutOfBounds(l_position);
3107//Console.WriteLine("ROOB 2");
3108
3109 return; // Dont process any other motion?
3110 } // end various methods
3111 } // end outside region horizontally
3112
3113
3114 if (l_position.Z < 0)
3115 {
3116 // This is so prim that get lost underground don't fall forever and suck up
3117 //
3118 // Sim resources and memory.
3119 // Disables the prim's movement physics....
3120 // It's a hack and will generate a console message if it fails.
3121
3122 //IsPhysical = false;
3123 if (_parent == null) base.RaiseOutOfBounds(_position);
3124//Console.WriteLine("ROOB 3");
3125
3126
3127 _acceleration.X = 0; // This stuff may stop client display but it has no
3128 _acceleration.Y = 0; // effect on the object in phys engine!
3129 _acceleration.Z = 0;
3130
3131 _velocity.X = 0;
3132 _velocity.Y = 0;
3133 _velocity.Z = 0;
3134 m_rotationalVelocity.X = 0;
3135 m_rotationalVelocity.Y = 0;
3136 m_rotationalVelocity.Z = 0;
3137
3138 if (_parent == null) base.RequestPhysicsterseUpdate();
3139
3140 m_throttleUpdates = false;
3141 throttleCounter = 0;
3142 _zeroFlag = true;
3143 //outofBounds = true;
3144 } // end neg Z check
3145
3146 // Is it moving?
3147 if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
3148 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
3149 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02)
3150 && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, _orientation)) < 0.0001)) // KF 0.01 is far to large
3151 {
3152 _zeroFlag = true;
3153 m_throttleUpdates = false;
3154 }
3155 else
3156 {
3157 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
3158 _zeroFlag = false;
3159 m_lastUpdateSent = false;
3160 //m_throttleUpdates = false;
3161 }
3162
3163 if (_zeroFlag)
3164 { // Its stopped
3165 _velocity.X = 0.0f;
3166 _velocity.Y = 0.0f;
3167 _velocity.Z = 0.0f;
3168
3169 _acceleration.X = 0;
3170 _acceleration.Y = 0;
3171 _acceleration.Z = 0;
3172
3173 m_rotationalVelocity.X = 0;
3174 m_rotationalVelocity.Y = 0;
3175 m_rotationalVelocity.Z = 0;
3176 if (!m_lastUpdateSent)
3177 {
3178 m_throttleUpdates = false;
3179 throttleCounter = 0;
3180 if (_parent == null)
3181 {
3182 base.RequestPhysicsterseUpdate();
3183 }
3184
3185 m_lastUpdateSent = true;
3186 }
3187 }
3188 else
3189 { // Its moving
3190 if (lastZeroFlag != _zeroFlag)
3191 {
3192 if (_parent == null)
3193 {
3194 base.RequestPhysicsterseUpdate();
3195 }
3196 }
3197 m_lastUpdateSent = false;
3198 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
3199 {
3200 if (_parent == null)
3201 {
3202 base.RequestPhysicsterseUpdate();
3203 }
3204 }
3205 else
3206 {
3207 throttleCounter++;
3208 }
3209 }
3210 m_lastposition = l_position;
3211
3212 /// End UpdatePositionAndVelocity insert
3213
3214
3215 // Rotation lock =====================================
3216 if(m_rotateEnableUpdate)
3217 {
3218 // Snapshot current angles, set up Amotor(s)
3219 m_rotateEnableUpdate = false;
3220 m_rotateEnable = m_rotateEnableRequest;
3221Console.WriteLine("RotEnable {0} = {1}",m_primName, m_rotateEnable);
3222
3223 if (Amotor != IntPtr.Zero)
3224 {
3225 d.JointDestroy(Amotor);
3226 Amotor = IntPtr.Zero;
3227Console.WriteLine("Old Amotor Destroyed");
3228 }
3229
3230 if (!m_rotateEnable.ApproxEquals(Vector3.One, 0.003f))
3231 { // not all are enabled
3232 d.Quaternion r = d.BodyGetQuaternion(Body);
3233 Quaternion locrot = new Quaternion(r.X, r.Y, r.Z, r.W);
3234 // extract the axes vectors
3235 Vector3 vX = new Vector3(1f,0f,0f);
3236 Vector3 vY = new Vector3(0f,1f,0f);
3237 Vector3 vZ = new Vector3(0f,0f,1f);
3238 vX = vX * locrot;
3239 vY = vY * locrot;
3240 vZ = vZ * locrot;
3241 // snapshot the current angle vectors
3242 m_lockX = vX;
3243 m_lockY = vY;
3244 m_lockZ = vZ;
3245 // m_lockRot = locrot;
3246 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3247 d.JointAttach(Amotor, Body, IntPtr.Zero);
3248 d.JointSetAMotorMode(Amotor, 0); // User mode??
3249Console.WriteLine("New Amotor Created for {0}", m_primName);
3250
3251 float axisnum = 3; // how many to lock
3252 axisnum = (axisnum - (m_rotateEnable.X + m_rotateEnable.Y + m_rotateEnable.Z));
3253 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3254Console.WriteLine("AxisNum={0}",(int)axisnum);
3255
3256 int i = 0;
3257
3258 if (m_rotateEnable.X == 0)
3259 {
3260 d.JointSetAMotorAxis(Amotor, i, 0, m_lockX.X, m_lockX.Y, m_lockX.Z);
3261Console.WriteLine("AxisX {0} set to {1}", i, m_lockX);
3262 i++;
3263 }
3264
3265 if (m_rotateEnable.Y == 0)
3266 {
3267 d.JointSetAMotorAxis(Amotor, i, 0, m_lockY.X, m_lockY.Y, m_lockY.Z);
3268Console.WriteLine("AxisY {0} set to {1}", i, m_lockY);
3269 i++;
3270 }
3271
3272 if (m_rotateEnable.Z == 0)
3273 {
3274 d.JointSetAMotorAxis(Amotor, i, 0, m_lockZ.X, m_lockZ.Y, m_lockZ.Z);
3275Console.WriteLine("AxisZ {0} set to {1}", i, m_lockZ);
3276 i++;
3277 }
3278
3279 // These lowstops and high stops are effectively (no wiggle room)
3280 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0f);
3281 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
3282 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0f);
3283 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3284 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3285 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3286 d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 0f);
3287 d.JointSetAMotorParam(Amotor, (int) dParam.Vel3, 0f);
3288 d.JointSetAMotorParam(Amotor, (int) dParam.Vel2, 0f);
3289 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM, 0f);
3290 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM3, 0f);
3291 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM2, 0f);
3292 } // else none are locked
3293 } // end Rotation Update
3294
3295
3296 // VEHICLE processing ==========================================
3297 if (m_type != Vehicle.TYPE_NONE)
3298 {
3299 // get body attitude
3300 d.Quaternion rot = d.BodyGetQuaternion(Body);
3301 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
3302 Quaternion irotq = Quaternion.Inverse(rotq);
3303
3304 // VEHICLE Linear Motion
3305 d.Vector3 velnow = d.BodyGetLinearVel(Body); // this is in world frame
3306 Vector3 vel_now = new Vector3(velnow.X, velnow.Y, velnow.Z);
3307 m_lLinObjectVel = vel_now * irotq;
3308
3309 if (m_linearMotorDecayTimescale < 300.0f) //setting of 300 or more disables decay rate
3310 {
3311 if ( Vector3.Mag(m_lLinMotorDVel) < 1.0f)
3312 {
3313 float decayfactor = m_linearMotorDecayTimescale/timestep;
3314 Vector3 decayAmount = (m_lLinMotorDVel/decayfactor);
3315 m_lLinMotorDVel -= decayAmount;
3316 }
3317 else
3318 {
3319 float decayfactor = 3.0f - (0.57f * (float)Math.Log((double)(m_linearMotorDecayTimescale)));
3320 Vector3 decel = Vector3.Normalize(m_lLinMotorDVel) * decayfactor * timestep;
3321 m_lLinMotorDVel -= decel;
3322 }
3323 if (m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3324 {
3325 m_lLinMotorDVel = Vector3.Zero;
3326 }
3327
3328 /* else
3329 {
3330 if (Math.Abs(m_lLinMotorDVel.X) < Math.Abs(m_lLinObjectVel.X)) m_lLinObjectVel.X = m_lLinMotorDVel.X;
3331 if (Math.Abs(m_lLinMotorDVel.Y) < Math.Abs(m_lLinObjectVel.Y)) m_lLinObjectVel.Y = m_lLinMotorDVel.Y;
3332 if (Math.Abs(m_lLinMotorDVel.Z) < Math.Abs(m_lLinObjectVel.Z)) m_lLinObjectVel.Z = m_lLinMotorDVel.Z;
3333 } */
3334 } // end linear motor decay
3335
3336 if ( (! m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! m_lLinObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3337 {
3338 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3339 if (m_linearMotorTimescale < 300.0f)
3340 {
3341 Vector3 attack_error = m_lLinMotorDVel - m_lLinObjectVel;
3342 float linfactor = m_linearMotorTimescale/timestep;
3343 Vector3 attackAmount = (attack_error/linfactor) * 1.3f;
3344 m_lLinObjectVel += attackAmount;
3345 }
3346 if (m_linearFrictionTimescale.X < 300.0f)
3347 {
3348 float fricfactor = m_linearFrictionTimescale.X / timestep;
3349 float fricX = m_lLinObjectVel.X / fricfactor;
3350 m_lLinObjectVel.X -= fricX;
3351 }
3352 if (m_linearFrictionTimescale.Y < 300.0f)
3353 {
3354 float fricfactor = m_linearFrictionTimescale.Y / timestep;
3355 float fricY = m_lLinObjectVel.Y / fricfactor;
3356 m_lLinObjectVel.Y -= fricY;
3357 }
3358 if (m_linearFrictionTimescale.Z < 300.0f)
3359 {
3360 float fricfactor = m_linearFrictionTimescale.Z / timestep;
3361 float fricZ = m_lLinObjectVel.Z / fricfactor;
3362 m_lLinObjectVel.Z -= fricZ;
3363 }
3364 }
3365 m_wLinObjectVel = m_lLinObjectVel * rotq;
3366
3367 // Gravity and Buoyancy
3368 Vector3 grav = Vector3.Zero;
3369 if(m_VehicleBuoyancy < 1.0f)
3370 {
3371 // There is some gravity, make a gravity force vector
3372 // that is applied after object velocity.
3373 d.Mass objMass;
3374 d.BodyGetMass(Body, out objMass);
3375 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
3376 grav.Z = _parent_scene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); // Applied later as a force
3377 } // else its 1.0, no gravity.
3378
3379 // Hovering
3380 if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
3381 {
3382 // We should hover, get the target height
3383 d.Vector3 pos = d.BodyGetPosition(Body);
3384 if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY)
3385 {
3386 m_VhoverTargetHeight = _parent_scene.GetWaterLevel() + m_VhoverHeight;
3387 }
3388 else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY)
3389 {
3390 m_VhoverTargetHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
3391 }
3392 else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT)
3393 {
3394 m_VhoverTargetHeight = m_VhoverHeight;
3395 }
3396
3397 if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY)
3398 {
3399 // If body is aready heigher, use its height as target height
3400 if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
3401 }
3402
3403// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
3404// m_VhoverTimescale = 0f; // time to acheive height
3405// timestep is time since last frame,in secs
3406 float herr0 = pos.Z - m_VhoverTargetHeight;
3407 // Replace Vertical speed with correction figure if significant
3408 if(Math.Abs(herr0) > 0.01f )
3409 {
3410 //? d.Mass objMass;
3411 //? d.BodyGetMass(Body, out objMass);
3412 m_wLinObjectVel.Z = - ( (herr0 * timestep * 50.0f) / m_VhoverTimescale);
3413 //KF: m_VhoverEfficiency is not yet implemented
3414 }
3415 else
3416 {
3417 m_wLinObjectVel.Z = 0f;
3418 }
3419 }
3420 else
3421 { // not hovering
3422 if (m_wLinObjectVel.Z == 0f)
3423 { // Gravity rules
3424 m_wLinObjectVel.Z = vel_now.Z;
3425 } // else the motor has it
3426 }
3427 linvel = m_wLinObjectVel;
3428
3429 // Vehicle Linear Motion done =======================================
3430 // Apply velocity
3431 d.BodySetLinearVel(Body, linvel.X, linvel.Y, linvel.Z);
3432 // apply gravity force
3433 d.BodyAddForce(Body, grav.X, grav.Y, grav.Z);
3434//if(frcount == 0) Console.WriteLine("Grav {0}", grav);
3435 // end MoveLinear()
3436
3437
3438 // MoveAngular
3439 /*
3440 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
3441
3442 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
3443 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
3444 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
3445
3446 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
3447 private Vector3 m_angObjectVel = Vector3.Zero; // what was last applied to body
3448 */
3449//if(frcount == 0) Console.WriteLine("MoveAngular ");
3450
3451 d.Vector3 angularObjectVel = d.BodyGetAngularVel(Body);
3452 Vector3 angObjectVel = new Vector3(angularObjectVel.X, angularObjectVel.Y, angularObjectVel.Z);
3453 angObjectVel = angObjectVel * irotq; // ============ Converts to LOCAL rotation
3454
3455//if(frcount == 0) Console.WriteLine("V0 = {0}", angObjectVel);
3456
3457 // Decay Angular Motor 1. In SL this also depends on attack rate! decay ~= 23/Attack.
3458 float atk_decayfactor = 23.0f / (m_angularMotorTimescale * timestep);
3459 m_angularMotorDVel -= m_angularMotorDVel / atk_decayfactor;
3460 // Decay Angular Motor 2.
3461 if (m_angularMotorDecayTimescale < 300.0f)
3462 {
3463 if ( Vector3.Mag(m_angularMotorDVel) < 1.0f)
3464 {
3465 float decayfactor = (m_angularMotorDecayTimescale)/timestep;
3466 Vector3 decayAmount = (m_angularMotorDVel/decayfactor);
3467 m_angularMotorDVel -= decayAmount;
3468 }
3469 else
3470 {
3471 Vector3 decel = Vector3.Normalize(m_angularMotorDVel) * timestep / m_angularMotorDecayTimescale;
3472 m_angularMotorDVel -= decel;
3473 }
3474
3475 if (m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3476 {
3477 m_angularMotorDVel = Vector3.Zero;
3478 }
3479 else
3480 {
3481 if (Math.Abs(m_angularMotorDVel.X) < Math.Abs(angObjectVel.X)) angObjectVel.X = m_angularMotorDVel.X;
3482 if (Math.Abs(m_angularMotorDVel.Y) < Math.Abs(angObjectVel.Y)) angObjectVel.Y = m_angularMotorDVel.Y;
3483 if (Math.Abs(m_angularMotorDVel.Z) < Math.Abs(angObjectVel.Z)) angObjectVel.Z = m_angularMotorDVel.Z;
3484 }
3485 } // end decay angular motor
3486//if(frcount == 0) Console.WriteLine("MotorDvel {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3487
3488//if(frcount == 0) Console.WriteLine("VA = {0}", angObjectVel);
3489
3490 if ( (! m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! angObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3491 { // if motor or object have motion
3492 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3493
3494 if (m_angularMotorTimescale < 300.0f)
3495 {
3496 Vector3 attack_error = m_angularMotorDVel - angObjectVel;
3497 float angfactor = m_angularMotorTimescale/timestep;
3498 Vector3 attackAmount = (attack_error/angfactor);
3499 angObjectVel += attackAmount;
3500//if(frcount == 0) Console.WriteLine("Accel {0} Attk {1}",FrAaccel, attackAmount);
3501//if(frcount == 0) Console.WriteLine("V2+= {0}", angObjectVel);
3502 }
3503
3504 angObjectVel.X -= angObjectVel.X / (m_angularFrictionTimescale.X * 0.7f / timestep);
3505 angObjectVel.Y -= angObjectVel.Y / (m_angularFrictionTimescale.Y * 0.7f / timestep);
3506 angObjectVel.Z -= angObjectVel.Z / (m_angularFrictionTimescale.Z * 0.7f / timestep);
3507 } // else no signif. motion
3508
3509//if(frcount == 0) Console.WriteLine("Dmotor {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3510 // Bank section tba
3511 // Deflection section tba
3512//if(frcount == 0) Console.WriteLine("V3 = {0}", angObjectVel);
3513
3514
3515 /* // Rotation Axis Disables:
3516 if (!m_angularEnable.ApproxEquals(Vector3.One, 0.003f))
3517 {
3518 if (m_angularEnable.X == 0)
3519 angObjectVel.X = 0f;
3520 if (m_angularEnable.Y == 0)
3521 angObjectVel.Y = 0f;
3522 if (m_angularEnable.Z == 0)
3523 angObjectVel.Z = 0f;
3524 }
3525 */
3526 angObjectVel = angObjectVel * rotq; // ================ Converts to WORLD rotation
3527
3528 // Vertical attractor section
3529 Vector3 vertattr = Vector3.Zero;
3530
3531 if(m_verticalAttractionTimescale < 300)
3532 {
3533 float VAservo = 1.0f / (m_verticalAttractionTimescale * timestep);
3534 // make a vector pointing up
3535 Vector3 verterr = Vector3.Zero;
3536 verterr.Z = 1.0f;
3537 // rotate it to Body Angle
3538 verterr = verterr * rotq;
3539 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
3540 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
3541 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
3542
3543 if (verterr.Z < 0.0f)
3544 { // Deflection from vertical exceeds 90-degrees. This method will ensure stable return to
3545 // vertical, BUT for some reason a z-rotation is imparted to the object. TBI.
3546//Console.WriteLine("InvertFlip");
3547 verterr.X = 2.0f - verterr.X;
3548 verterr.Y = 2.0f - verterr.Y;
3549 }
3550 verterr *= 0.5f;
3551 // verterror is 0 (no error) to +/- 1 (max error at 180-deg tilt)
3552 Vector3 xyav = angObjectVel;
3553 xyav.Z = 0.0f;
3554 if ((!xyav.ApproxEquals(Vector3.Zero, 0.001f)) || (verterr.Z < 0.49f))
3555 {
3556 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
3557 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
3558 vertattr.X = verterr.Y;
3559 vertattr.Y = - verterr.X;
3560 vertattr.Z = 0f;
3561//if(frcount == 0) Console.WriteLine("VAerr=" + verterr);
3562
3563 // scaling appears better usingsquare-law
3564 float damped = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
3565 float bounce = 1.0f - damped;
3566 // 0 = crit damp, 1 = bouncy
3567 float oavz = angObjectVel.Z; // retain z velocity
3568 // time-scaled correction, which sums, therefore is bouncy:
3569 angObjectVel = (angObjectVel + (vertattr * VAservo * 0.0333f)) * bounce;
3570 // damped, good @ < 90:
3571 angObjectVel = angObjectVel + (vertattr * VAservo * 0.0667f * damped);
3572 angObjectVel.Z = oavz;
3573//if(frcount == 0) Console.WriteLine("VA+");
3574//Console.WriteLine("VAttr {0} OAvel {1}", vertattr, angObjectVel);
3575 }
3576 else
3577 {
3578 // else error is very small
3579 angObjectVel.X = 0f;
3580 angObjectVel.Y = 0f;
3581//if(frcount == 0) Console.WriteLine("VA0");
3582 }
3583 } // else vertical attractor is off
3584//if(frcount == 0) Console.WriteLine("V1 = {0}", angObjectVel);
3585
3586
3587 m_lastAngularVelocity = angObjectVel;
3588 // apply Angular Velocity to body
3589 d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z);
3590//if(frcount == 0) Console.WriteLine("V4 = {0}", m_lastAngularVelocity);
3591
3592 } // end VEHICLES
3593 else
3594 {
3595 // Dyamics (NON-'VEHICLES') are dealt with here ================================================================
3596
3597 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009
3598
3599 /// Dynamics Buoyancy
3600 //KF: m_buoyancy is set by llSetBuoyancy() and is for non-vehicle.
3601 // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up
3602 // NB Prims in ODE are no subject to global gravity
3603 // This should only affect gravity operations
3604
3605 float m_mass = CalculateMass();
3606 // calculate z-force due togravity on object.
3607 fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; // force = acceleration * mass
3608
3609 if ((m_usePID) && (m_PIDTau > 0.0f)) // Dynamics llMoveToTarget.
3610 {
3611 fz = 0; // llMoveToTarget ignores gravity.
3612 // it also ignores mass of object, and any physical resting on it.
3613 // Vector3 m_PIDTarget is where we are going
3614 // float m_PIDTau is time to get there
3615 fx = 0;
3616 fy = 0;
3617 d.Vector3 pos = d.BodyGetPosition(Body);
3618 Vector3 error = new Vector3(
3619 (m_PIDTarget.X - pos.X),
3620 (m_PIDTarget.Y - pos.Y),
3621 (m_PIDTarget.Z - pos.Z));
3622 if (error.ApproxEquals(Vector3.Zero,0.01f))
3623 { // Very close, Jump there and quit move
3624 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3625 _target_velocity = Vector3.Zero;
3626 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3627 }
3628 else
3629 {
3630 float scale = 50.0f * timestep / m_PIDTau;
3631 if ((error.ApproxEquals(Vector3.Zero,0.5f)) && (_target_velocity != Vector3.Zero))
3632 {
3633 // Nearby, quit update of velocity
3634 }
3635 else
3636 { // Far, calc damped velocity
3637 _target_velocity = error * scale;
3638 }
3639 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3640 }
3641 } // end PID MoveToTarget
3642
3643 /* Original OS implementation: Does not work correctly as another phys object resting on THIS object purturbs its position.
3644 This is incorrect behavior. llMoveToTarget must move the Body no matter what phys object is resting on it.
3645
3646 //if (!d.BodyIsEnabled(Body))
3647 //d.BodySetForce(Body, 0f, 0f, 0f);
3648
3649 // no lock; for now it's only called from within Simulate()
3650
3651 // If the PID Controller isn't active then we set our force
3652 // calculating base velocity to the current position
3653
3654 if ((m_PIDTau < 1) && (m_PIDTau != 0))
3655 {
3656 //PID_G = PID_G / m_PIDTau;
3657 m_PIDTau = 1;
3658 }
3659
3660 if ((PID_G - m_PIDTau) <= 0)
3661 {
3662 PID_G = m_PIDTau + 1;
3663 }
3664 //PidStatus = true;
3665
3666 // PhysicsVector vec = new PhysicsVector();
3667// d.Vector3 vel = d.BodyGetLinearVel(Body);
3668
3669 d.Vector3 pos = d.BodyGetPosition(Body);
3670 _target_velocity =
3671 new Vector3(
3672 (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep),
3673 (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep),
3674 (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep)
3675 );
3676
3677if(frcount == 0) Console.WriteLine("PID {0} b={1} fz={2} vel={3}", m_primName, m_buoyancy, fz, _target_velocity);
3678 // if velocity is zero, use position control; otherwise, velocity control
3679
3680 if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f))
3681 {
3682 // keep track of where we stopped. No more slippin' & slidin'
3683
3684 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3685 // react to the physics scene by moving it's position.
3686 // Avatar to Avatar collisions
3687 // Prim to avatar collisions
3688
3689 //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
3690 //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2);
3691 //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
3692 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3693 d.BodySetLinearVel(Body, 0, 0, 0);
3694 d.BodyAddForce(Body, 0, 0, fz);
3695 // return;
3696 }
3697 else
3698 {
3699 _zeroFlag = false;
3700
3701 // We're flying and colliding with something
3702 fx = ((_target_velocity.X) - vel.X) * (PID_D);
3703 fy = ((_target_velocity.Y) - vel.Y) * (PID_D);
3704
3705 // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
3706
3707 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3708 }
3709 } // end if (m_usePID)
3710 End of old PID system */
3711
3712
3713 /// Dynamics Hover ===================================================================================
3714 // Hover PID Controller can only run if the PIDcontroller is not in use.
3715 if (m_useHoverPID && !m_usePID)
3716 {
3717//Console.WriteLine("Hover " + m_primName);
3718
3719 // If we're using the PID controller, then we have no gravity
3720 fz = (-1 * _parent_scene.gravityz) * m_mass;
3721
3722 // no lock; for now it's only called from within Simulate()
3723
3724 // If the PID Controller isn't active then we set our force
3725 // calculating base velocity to the current position
3726
3727 if ((m_PIDTau < 1))
3728 {
3729 PID_G = PID_G / m_PIDTau;
3730 }
3731
3732 if ((PID_G - m_PIDTau) <= 0)
3733 {
3734 PID_G = m_PIDTau + 1;
3735 }
3736
3737
3738 // Where are we, and where are we headed?
3739 d.Vector3 pos = d.BodyGetPosition(Body);
3740// d.Vector3 vel = d.BodyGetLinearVel(Body);
3741
3742
3743 // Non-Vehicles have a limited set of Hover options.
3744 // determine what our target height really is based on HoverType
3745 switch (m_PIDHoverType)
3746 {
3747 case PIDHoverType.Ground:
3748 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3749 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3750 break;
3751 case PIDHoverType.GroundAndWater:
3752 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3753 m_waterHeight = _parent_scene.GetWaterLevel();
3754 if (m_groundHeight > m_waterHeight)
3755 {
3756 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3757 }
3758 else
3759 {
3760 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
3761 }
3762 break;
3763
3764 } // end switch (m_PIDHoverType)
3765
3766
3767 _target_velocity =
3768 new Vector3(0.0f, 0.0f,
3769 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
3770 );
3771
3772 // if velocity is zero, use position control; otherwise, velocity control
3773
3774 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
3775 {
3776 // keep track of where we stopped. No more slippin' & slidin'
3777
3778 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3779 // react to the physics scene by moving it's position.
3780 // Avatar to Avatar collisions
3781 // Prim to avatar collisions
3782 d.Vector3 dlinvel = vel;
3783
3784 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
3785 d.BodySetLinearVel(Body, dlinvel.X, dlinvel.Y, dlinvel.Z);
3786 d.BodyAddForce(Body, 0, 0, fz);
3787 //KF this prevents furthur motions return;
3788 }
3789 else
3790 {
3791 _zeroFlag = false;
3792
3793 // We're flying and colliding with something
3794 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3795 }
3796 } // end m_useHoverPID && !m_usePID
3797
3798 /// Dynamics RotLookAt =================================================================================
3799 if (m_useAPID)
3800 {
3801 // RotLookAt, apparently overrides all other rotation sources. Inputs:
3802 // Quaternion m_APIDTarget
3803 // float m_APIDStrength // From SL experiments, this is the time to get there
3804 // float m_APIDDamping // From SL experiments, this is damping, 1.0 = damped, 0.1 = wobbly
3805 // Also in SL the mass of the object has no effect on time to get there.
3806 // Factors:
3807 // get present body rotation
3808 float limit = 1.0f;
3809 float scaler = 50f; // adjusts damping time
3810 float RLAservo = 0f;
3811
3812 d.Quaternion rot = d.BodyGetQuaternion(Body);
3813 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
3814 Quaternion rot_diff = Quaternion.Inverse(rotq) * m_APIDTarget;
3815 float diff_angle;
3816 Vector3 diff_axis;
3817 rot_diff.GetAxisAngle(out diff_axis, out diff_angle);
3818 diff_axis.Normalize();
3819 if(diff_angle > 0.01f) // diff_angle is always +ve
3820 {
3821// PhysicsVector rotforce = new PhysicsVector(diff_axis.X, diff_axis.Y, diff_axis.Z);
3822 Vector3 rotforce = new Vector3(diff_axis.X, diff_axis.Y, diff_axis.Z);
3823 rotforce = rotforce * rotq;
3824 if(diff_angle > limit) diff_angle = limit; // cap the rotate rate
3825// RLAservo = timestep / m_APIDStrength * m_mass * scaler;
3826 // rotforce = rotforce * RLAservo * diff_angle ;
3827 // d.BodyAddRelTorque(Body, rotforce.X, rotforce.Y, rotforce.Z);
3828 RLAservo = timestep / m_APIDStrength * scaler;
3829 rotforce = rotforce * RLAservo * diff_angle ;
3830 /*
3831 if (m_angularEnable.X == 0)
3832 rotforce.X = 0;
3833 if (m_angularEnable.Y == 0)
3834 rotforce.Y = 0;
3835 if (m_angularEnable.Z == 0)
3836 rotforce.Z = 0;
3837 */
3838 d.BodySetAngularVel (Body, rotforce.X, rotforce.Y, rotforce.Z);
3839//Console.WriteLine("axis= " + diff_axis + " angle= " + diff_angle + "servo= " + RLAservo);
3840 }
3841//if(frcount == 0) Console.WriteLine("mass= " + m_mass + " servo= " + RLAservo + " angle= " + diff_angle);
3842 } // end m_useAPID
3843
3844 /// Dynamics Apply Forces ===================================================================================
3845 fx *= m_mass;
3846 fy *= m_mass;
3847 //fz *= m_mass;
3848
3849 fx += m_force.X;
3850 fy += m_force.Y;
3851 fz += m_force.Z;
3852
3853 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
3854 if (fx != 0 || fy != 0 || fz != 0)
3855 {
3856 //m_taintdisable = true;
3857 //base.RaiseOutOfBounds(Position);
3858 //d.BodySetLinearVel(Body, fx, fy, 0f);
3859 if (!d.BodyIsEnabled(Body))
3860 {
3861 // A physical body at rest on a surface will auto-disable after a while,
3862 // this appears to re-enable it incase the surface it is upon vanishes,
3863 // and the body should fall again.
3864 d.BodySetLinearVel(Body, 0f, 0f, 0f);
3865 d.BodySetForce(Body, 0, 0, 0);
3866 enableBodySoft();
3867 }
3868
3869 // 35x10 = 350n times the mass per second applied maximum.
3870 float nmax = 35f * m_mass;
3871 float nmin = -35f * m_mass;
3872
3873
3874 if (fx > nmax)
3875 fx = nmax;
3876 if (fx < nmin)
3877 fx = nmin;
3878 if (fy > nmax)
3879 fy = nmax;
3880 if (fy < nmin)
3881 fy = nmin;
3882 d.BodyAddForce(Body, fx, fy, fz);
3883//Console.WriteLine("AddForce " + fx + "," + fy + "," + fz);
3884 } // end apply forces
3885 } // end Dynamics
3886
3887/* obsolete?
3888 else
3889 { // is not physical, or is not a body or is selected
3890 // from old UpdatePositionAndVelocity, ... Not a body.. so Make sure the client isn't interpolating
3891 _velocity.X = 0;
3892 _velocity.Y = 0;
3893 _velocity.Z = 0;
3894
3895 _acceleration.X = 0;
3896 _acceleration.Y = 0;
3897 _acceleration.Z = 0;
3898
3899 m_rotationalVelocity.X = 0;
3900 m_rotationalVelocity.Y = 0;
3901 m_rotationalVelocity.Z = 0;
3902 _zeroFlag = true;
3903 return;
3904 }
3905 */
3906 } // end root prims
3907
3908 } // end Move()
3909 } // end class
3910}