aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs')
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs3573
1 files changed, 3573 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
new file mode 100644
index 0000000..b105f77
--- /dev/null
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
@@ -0,0 +1,3573 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* Revision 2011/12 by Ubit Umarov
29 *
30 *
31 */
32
33/*
34 * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces
35 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
36 * ODEPrim.cs contains methods dealing with Prim editing, Prim
37 * characteristics and Kinetic motion.
38 * ODEDynamics.cs contains methods dealing with Prim Physical motion
39 * (dynamics) and the associated settings. Old Linear and angular
40 * motors for dynamic motion have been replace with MoveLinear()
41 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
42 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
43 * switch between 'VEHICLE' parameter use and general dynamics
44 * settings use.
45 */
46
47//#define SPAM
48
49using System;
50using System.Collections.Generic;
51using System.Reflection;
52using System.Runtime.InteropServices;
53using System.Threading;
54using log4net;
55using OpenMetaverse;
56using OdeAPI;
57using OpenSim.Framework;
58using OpenSim.Region.Physics.Manager;
59
60
61namespace OpenSim.Region.Physics.OdePlugin
62{
63 public class OdePrim : PhysicsActor
64 {
65 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
66
67 private bool m_isphysical;
68 private bool m_fakeisphysical;
69
70 protected bool m_building;
71 private Quaternion m_lastorientation = new Quaternion();
72 private Quaternion _orientation;
73
74 private Vector3 _position;
75 private Vector3 _velocity;
76 private Vector3 _torque;
77 private Vector3 m_lastVelocity;
78 private Vector3 m_lastposition;
79 private Vector3 m_rotationalVelocity;
80 private Vector3 _size;
81 private Vector3 _acceleration;
82 private Vector3 m_angularlock = Vector3.One;
83 private IntPtr Amotor = IntPtr.Zero;
84
85 private Vector3 m_force;
86 private Vector3 m_forceacc;
87 private Vector3 m_angularForceacc;
88
89 private Vector3 m_PIDTarget;
90 private float m_PIDTau;
91 private float PID_D = 35f;
92 private float PID_G = 25f;
93 private bool m_usePID;
94
95 // KF: These next 7 params apply to llSetHoverHeight(float height, integer water, float tau),
96 // and are for non-VEHICLES only.
97
98 private float m_PIDHoverHeight;
99 private float m_PIDHoverTau;
100 private bool m_useHoverPID;
101 private PIDHoverType m_PIDHoverType = PIDHoverType.Ground;
102 private float m_targetHoverHeight;
103 private float m_groundHeight;
104 private float m_waterHeight;
105 private float m_buoyancy; //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle.
106
107 private int body_autodisable_frames = 20;
108
109 private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
110 | CollisionCategories.Space
111 | CollisionCategories.Body
112 | CollisionCategories.Character
113 );
114// private bool m_collidesLand = true;
115 private bool m_collidesWater;
116 public bool m_returnCollisions;
117 private bool m_softcolide;
118
119 private bool m_NoColide; // for now only for internal use for bad meshs
120
121 // Default we're a Geometry
122 private CollisionCategories m_collisionCategories = (CollisionCategories.Geom);
123
124 // Default, Collide with Other Geometries, spaces and Bodies
125 private CollisionCategories m_collisionFlags = m_default_collisionFlags;
126
127 public bool m_disabled;
128
129
130 public uint m_localID;
131
132 private PrimitiveBaseShape _pbs;
133 public OdeScene _parent_scene;
134
135 /// <summary>
136 /// The physics space which contains prim geometry
137 /// </summary>
138 public IntPtr m_targetSpace = IntPtr.Zero;
139
140 public IntPtr prim_geom;
141 public IntPtr _triMeshData;
142
143 private PhysicsActor _parent;
144
145 private List<OdePrim> childrenPrim = new List<OdePrim>();
146
147 private bool m_iscolliding;
148
149 public bool m_isSelected;
150 private bool m_delaySelect;
151 private bool m_lastdoneSelected;
152 public bool m_outbounds;
153
154 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
155
156 private bool m_throttleUpdates;
157 private int throttleCounter;
158 public float m_collisionscore;
159 int m_colliderfilter = 0;
160
161 public IntPtr collide_geom; // for objects: geom if single prim space it linkset
162
163 private float m_density = 10.000006836f; // Aluminum g/cm3;
164
165 public bool _zeroFlag;
166 private bool m_lastUpdateSent;
167
168 public IntPtr Body = IntPtr.Zero;
169 public String Name { get; private set; }
170 private Vector3 _target_velocity;
171
172 public Vector3 primOOBsize; // prim real dimensions from mesh
173 public Vector3 primOOBoffset; // its centroid out of mesh or rest aabb
174 public float primOOBradiusSQ;
175 public d.Mass primdMass; // prim inertia information on it's own referencial
176 float primMass; // prim own mass
177 float _mass; // object mass acording to case
178 private bool hasOOBoffsetFromMesh = false; // if true we did compute it form mesh centroid, else from aabb
179
180 public int givefakepos = 0;
181 private Vector3 fakepos;
182 public int givefakeori = 0;
183 private Quaternion fakeori;
184
185 public int m_eventsubscription;
186 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
187
188 public volatile bool childPrim;
189
190 public ODEDynamics m_vehicle;
191
192 internal int m_material = (int)Material.Wood;
193 private float mu;
194 private float bounce;
195
196 /// <summary>
197 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
198 /// </summary>
199 public override bool IsPhysical // this is not reliable for internal use
200 {
201 get { return m_fakeisphysical; }
202 set
203 {
204 m_fakeisphysical = value; // we show imediatly to outside that we changed physical
205 // and also to stop imediatly some updates
206 // but real change will only happen in taintprocessing
207
208 if (!value) // Zero the remembered last velocity
209 m_lastVelocity = Vector3.Zero;
210 AddChange(changes.Physical, value);
211 }
212 }
213
214 public override bool Building // this is not reliable for internal use
215 {
216 get { return m_building; }
217 set
218 {
219 if (value)
220 m_building = true;
221 AddChange(changes.building, value);
222 }
223 }
224
225 public override void getContactData(ref ContactData cdata)
226 {
227 cdata.mu = mu;
228 cdata.bounce = bounce;
229
230 // cdata.softcolide = m_softcolide;
231 cdata.softcolide = false;
232
233 if (m_isphysical)
234 {
235 ODEDynamics veh;
236 if (_parent != null)
237 veh = ((OdePrim)_parent).m_vehicle;
238 else
239 veh = m_vehicle;
240
241 if (veh != null && veh.Type != Vehicle.TYPE_NONE)
242 cdata.mu *= veh.FrictionFactor;
243 }
244 }
245
246 public override int PhysicsActorType
247 {
248 get { return (int)ActorTypes.Prim; }
249 set { return; }
250 }
251
252 public override bool SetAlwaysRun
253 {
254 get { return false; }
255 set { return; }
256 }
257
258 public override uint LocalID
259 {
260 get
261 {
262 return m_localID;
263 }
264 set
265 {
266 //m_log.Info("[PHYSICS]: Setting TrackerID: " + value);
267 m_localID = value;
268 }
269 }
270
271 public override bool Grabbed
272 {
273 set { return; }
274 }
275
276 public override bool Selected
277 {
278 set
279 {
280 if (value)
281 m_isSelected = value; // if true set imediatly to stop moves etc
282 AddChange(changes.Selected, value);
283 }
284 }
285
286 public override bool Flying
287 {
288 // no flying prims for you
289 get { return false; }
290 set { }
291 }
292
293 public override bool IsColliding
294 {
295 get { return m_iscolliding; }
296 set
297 {
298 if (value)
299 {
300 m_colliderfilter += 2;
301 if (m_colliderfilter > 2)
302 m_colliderfilter = 2;
303 }
304 else
305 {
306 m_colliderfilter--;
307 if (m_colliderfilter < 0)
308 m_colliderfilter = 0;
309 }
310
311 if (m_colliderfilter == 0)
312 {
313 m_softcolide = false;
314 m_iscolliding = false;
315 }
316 else
317 m_iscolliding = true;
318 }
319 }
320
321 public override bool CollidingGround
322 {
323 get { return false; }
324 set { return; }
325 }
326
327 public override bool CollidingObj
328 {
329 get { return false; }
330 set { return; }
331 }
332
333 public override bool ThrottleUpdates
334 {
335 get { return m_throttleUpdates; }
336 set { m_throttleUpdates = value; }
337 }
338
339 public override bool Stopped
340 {
341 get { return _zeroFlag; }
342 }
343
344 public override Vector3 Position
345 {
346 get
347 {
348 if (givefakepos > 0)
349 return fakepos;
350 else
351 return _position;
352 }
353
354 set
355 {
356 fakepos = value;
357 givefakepos++;
358 AddChange(changes.Position, value);
359 }
360 }
361
362 public override Vector3 Size
363 {
364 get { return _size; }
365 set
366 {
367 if (value.IsFinite())
368 {
369 AddChange(changes.Size, value);
370 }
371 else
372 {
373 m_log.WarnFormat("[PHYSICS]: Got NaN Size on object {0}", Name);
374 }
375 }
376 }
377
378 public override float Mass
379 {
380 get { return _mass; }
381 }
382
383 public override Vector3 Force
384 {
385 //get { return Vector3.Zero; }
386 get { return m_force; }
387 set
388 {
389 if (value.IsFinite())
390 {
391 AddChange(changes.Force, value);
392 }
393 else
394 {
395 m_log.WarnFormat("[PHYSICS]: NaN in Force Applied to an Object {0}", Name);
396 }
397 }
398 }
399
400 public override void SetVolumeDetect(int param)
401 {
402 AddChange(changes.VolumeDtc, (param != 0));
403 }
404
405 public override Vector3 GeometricCenter
406 {
407 get
408 {
409 return Vector3.Zero;
410 }
411 }
412
413 public override Vector3 CenterOfMass
414 {
415 get
416 {
417 d.Vector3 dtmp;
418 if (IsPhysical && !childPrim && Body != IntPtr.Zero)
419 {
420 dtmp = d.BodyGetPosition(Body);
421 return new Vector3(dtmp.X, dtmp.Y, dtmp.Z);
422 }
423 else if (prim_geom != IntPtr.Zero)
424 {
425 d.Quaternion dq;
426 d.GeomCopyQuaternion(prim_geom, out dq);
427 Quaternion q;
428 q.X = dq.X;
429 q.Y = dq.Y;
430 q.Z = dq.Z;
431 q.W = dq.W;
432
433 Vector3 vtmp = primOOBoffset * q;
434 dtmp = d.GeomGetPosition(prim_geom);
435 return new Vector3(dtmp.X + vtmp.X, dtmp.Y + vtmp.Y, dtmp.Z + vtmp.Z);
436 }
437 else
438 return Vector3.Zero;
439 }
440 }
441 /*
442 public override Vector3 PrimOOBsize
443 {
444 get
445 {
446 return primOOBsize;
447 }
448 }
449
450 public override Vector3 PrimOOBoffset
451 {
452 get
453 {
454 return primOOBoffset;
455 }
456 }
457
458 public override float PrimOOBRadiusSQ
459 {
460 get
461 {
462 return primOOBradiusSQ;
463 }
464 }
465 */
466 public override PrimitiveBaseShape Shape
467 {
468 set
469 {
470 AddChange(changes.Shape, value);
471 }
472 }
473
474 public override Vector3 Velocity
475 {
476 get
477 {
478 if (_zeroFlag)
479 return Vector3.Zero;
480 return _velocity;
481 }
482 set
483 {
484 if (value.IsFinite())
485 {
486 AddChange(changes.Velocity, value);
487 // _velocity = value;
488
489 }
490 else
491 {
492 m_log.WarnFormat("[PHYSICS]: Got NaN Velocity in Object {0}", Name);
493 }
494
495 }
496 }
497
498 public override Vector3 Torque
499 {
500 get
501 {
502 if (!IsPhysical || Body == IntPtr.Zero)
503 return Vector3.Zero;
504
505 return _torque;
506 }
507
508 set
509 {
510 if (value.IsFinite())
511 {
512 AddChange(changes.Torque, value);
513 }
514 else
515 {
516 m_log.WarnFormat("[PHYSICS]: Got NaN Torque in Object {0}", Name);
517 }
518 }
519 }
520
521 public override float CollisionScore
522 {
523 get { return m_collisionscore; }
524 set { m_collisionscore = value; }
525 }
526
527 public override bool Kinematic
528 {
529 get { return false; }
530 set { }
531 }
532
533 public override Quaternion Orientation
534 {
535 get
536 {
537 if (givefakeori > 0)
538 return fakeori;
539 else
540
541 return _orientation;
542 }
543 set
544 {
545 if (QuaternionIsFinite(value))
546 {
547 fakeori = value;
548 givefakeori++;
549 AddChange(changes.Orientation, value);
550 }
551 else
552 m_log.WarnFormat("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object {0}", Name);
553
554 }
555 }
556
557 public override Vector3 Acceleration
558 {
559 get { return _acceleration; }
560 set { }
561 }
562
563 public override Vector3 RotationalVelocity
564 {
565 get
566 {
567 Vector3 pv = Vector3.Zero;
568 if (_zeroFlag)
569 return pv;
570 m_lastUpdateSent = false;
571
572 if (m_rotationalVelocity.ApproxEquals(pv, 0.0001f))
573 return pv;
574
575 return m_rotationalVelocity;
576 }
577 set
578 {
579 if (value.IsFinite())
580 {
581 m_rotationalVelocity = value;
582 if (Body != IntPtr.Zero && !d.BodyIsEnabled(Body))
583 d.BodyEnable(Body);
584 }
585 else
586 {
587 m_log.WarnFormat("[PHYSICS]: Got NaN RotationalVelocity in Object {0}", Name);
588 }
589 }
590 }
591
592
593 public override float Buoyancy
594 {
595 get { return m_buoyancy; }
596 set
597 {
598 m_buoyancy = value;
599 }
600 }
601
602 public override bool FloatOnWater
603 {
604 set
605 {
606 AddChange(changes.CollidesWater, value);
607 }
608 }
609
610 public override Vector3 PIDTarget
611 {
612 set
613 {
614 if (value.IsFinite())
615 {
616 m_PIDTarget = value;
617 }
618 else
619 m_log.WarnFormat("[PHYSICS]: Got NaN PIDTarget from Scene on Object {0}", Name);
620 }
621 }
622
623 public override bool PIDActive { set { m_usePID = value; } }
624 public override float PIDTau { set { m_PIDTau = value; } }
625
626 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
627 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
628 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
629 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
630
631 public override Quaternion APIDTarget { set { return; } }
632
633 public override bool APIDActive { set { return; } }
634
635 public override float APIDStrength { set { return; } }
636
637 public override float APIDDamping { set { return; } }
638
639 public override int VehicleType
640 {
641 // we may need to put a fake on this
642 get
643 {
644 if (m_vehicle == null)
645 return (int)Vehicle.TYPE_NONE;
646 else
647 return (int)m_vehicle.Type;
648 }
649 set
650 {
651 AddChange(changes.VehicleType, value);
652 }
653 }
654
655 public override void VehicleFloatParam(int param, float value)
656 {
657 strVehicleFloatParam fp = new strVehicleFloatParam();
658 fp.param = param;
659 fp.value = value;
660 AddChange(changes.VehicleFloatParam, fp);
661 }
662
663 public override void VehicleVectorParam(int param, Vector3 value)
664 {
665 strVehicleVectorParam fp = new strVehicleVectorParam();
666 fp.param = param;
667 fp.value = value;
668 AddChange(changes.VehicleVectorParam, fp);
669 }
670
671 public override void VehicleRotationParam(int param, Quaternion value)
672 {
673 strVehicleQuatParam fp = new strVehicleQuatParam();
674 fp.param = param;
675 fp.value = value;
676 AddChange(changes.VehicleRotationParam, fp);
677 }
678
679 public override void VehicleFlags(int param, bool value)
680 {
681 strVehicleBoolParam bp = new strVehicleBoolParam();
682 bp.param = param;
683 bp.value = value;
684 AddChange(changes.VehicleFlags, bp);
685 }
686
687 public override void SetVehicle(object vdata)
688 {
689 AddChange(changes.SetVehicle, vdata);
690 }
691 public void SetAcceleration(Vector3 accel)
692 {
693 _acceleration = accel;
694 }
695
696 public override void AddForce(Vector3 force, bool pushforce)
697 {
698 if (force.IsFinite())
699 {
700 AddChange(changes.AddForce, force / _parent_scene.ODE_STEPSIZE);
701 }
702 else
703 {
704 m_log.WarnFormat("[PHYSICS]: Got Invalid linear force vector from Scene in Object {0}", Name);
705 }
706 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
707 }
708
709 public override void AddAngularForce(Vector3 force, bool pushforce)
710 {
711 if (force.IsFinite())
712 {
713 AddChange(changes.AddAngForce, force / _parent_scene.ODE_STEPSIZE);
714 }
715 else
716 {
717 m_log.WarnFormat("[PHYSICS]: Got Invalid Angular force vector from Scene in Object {0}", Name);
718 }
719 }
720
721 public override void CrossingFailure()
722 {
723 if (m_outbounds)
724 {
725 _position.X = Util.Clip(_position.X, 0.5f, _parent_scene.WorldExtents.X - 0.5f);
726 _position.Y = Util.Clip(_position.Y, 0.5f, _parent_scene.WorldExtents.Y - 0.5f);
727 _position.Z = Util.Clip(_position.Z + 0.2f, -100f, 50000f);
728
729 m_lastposition = _position;
730 _velocity.X = 0;
731 _velocity.Y = 0;
732 _velocity.Z = 0;
733
734 m_lastVelocity = _velocity;
735 if (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE)
736 m_vehicle.Stop();
737
738 if(Body != IntPtr.Zero)
739 d.BodySetLinearVel(Body, 0, 0, 0); // stop it
740 if (prim_geom != IntPtr.Zero)
741 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
742
743 m_outbounds = false;
744 changeDisable(false);
745 base.RequestPhysicsterseUpdate();
746 }
747 }
748
749 public override void SetMomentum(Vector3 momentum)
750 {
751 }
752
753 public override void SetMaterial(int pMaterial)
754 {
755 m_material = pMaterial;
756 mu = _parent_scene.m_materialContactsData[pMaterial].mu;
757 bounce = _parent_scene.m_materialContactsData[pMaterial].bounce;
758 }
759
760 public void setPrimForRemoval()
761 {
762 AddChange(changes.Remove, null);
763 }
764
765 public override void link(PhysicsActor obj)
766 {
767 AddChange(changes.Link, obj);
768 }
769
770 public override void delink()
771 {
772 AddChange(changes.DeLink, null);
773 }
774
775 public override void LockAngularMotion(Vector3 axis)
776 {
777 // reverse the zero/non zero values for ODE.
778 if (axis.IsFinite())
779 {
780 axis.X = (axis.X > 0) ? 1f : 0f;
781 axis.Y = (axis.Y > 0) ? 1f : 0f;
782 axis.Z = (axis.Z > 0) ? 1f : 0f;
783 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
784 AddChange(changes.AngLock, axis);
785 }
786 else
787 {
788 m_log.WarnFormat("[PHYSICS]: Got NaN locking axis from Scene on Object {0}", Name);
789 }
790 }
791
792 public override void SubscribeEvents(int ms)
793 {
794 m_eventsubscription = ms;
795 _parent_scene.AddCollisionEventReporting(this);
796 }
797
798 public override void UnSubscribeEvents()
799 {
800 _parent_scene.RemoveCollisionEventReporting(this);
801 m_eventsubscription = 0;
802 }
803
804 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
805 {
806 if (CollisionEventsThisFrame == null)
807 CollisionEventsThisFrame = new CollisionEventUpdate();
808
809 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
810 }
811
812 public void SendCollisions()
813 {
814 if (CollisionEventsThisFrame == null)
815 return;
816
817 base.SendCollisionUpdate(CollisionEventsThisFrame);
818
819 if (CollisionEventsThisFrame.m_objCollisionList.Count == 0)
820 CollisionEventsThisFrame = null;
821 else
822 CollisionEventsThisFrame = new CollisionEventUpdate();
823 }
824
825 public override bool SubscribedEvents()
826 {
827 if (m_eventsubscription > 0)
828 return true;
829 return false;
830 }
831
832
833 public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
834 Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
835 {
836 Name = primName;
837
838 m_vehicle = null;
839
840 if (!pos.IsFinite())
841 {
842 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
843 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
844 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Position for {0}", Name);
845 }
846 _position = pos;
847 givefakepos = 0;
848
849 PID_D = parent_scene.bodyPIDD;
850 PID_G = parent_scene.bodyPIDG;
851 m_density = parent_scene.geomDefaultDensity;
852 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
853 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
854
855 prim_geom = IntPtr.Zero;
856 collide_geom = IntPtr.Zero;
857 Body = IntPtr.Zero;
858
859 if (!size.IsFinite())
860 {
861 size = new Vector3(0.5f, 0.5f, 0.5f);
862 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Size for {0}", Name);
863 }
864
865 if (size.X <= 0) size.X = 0.01f;
866 if (size.Y <= 0) size.Y = 0.01f;
867 if (size.Z <= 0) size.Z = 0.01f;
868
869 _size = size;
870
871 if (!QuaternionIsFinite(rotation))
872 {
873 rotation = Quaternion.Identity;
874 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Rotation for {0}", Name);
875 }
876
877 _orientation = rotation;
878 givefakeori = 0;
879
880 _pbs = pbs;
881
882 _parent_scene = parent_scene;
883 m_targetSpace = IntPtr.Zero;
884
885 if (pos.Z < 0)
886 {
887 m_isphysical = false;
888 }
889 else
890 {
891 m_isphysical = pisPhysical;
892 }
893 m_fakeisphysical = m_isphysical;
894
895 m_isVolumeDetect = false;
896
897 m_force = Vector3.Zero;
898
899 m_iscolliding = false;
900 m_colliderfilter = 0;
901 m_softcolide = true;
902 m_NoColide = false;
903
904 hasOOBoffsetFromMesh = false;
905 _triMeshData = IntPtr.Zero;
906
907 m_lastdoneSelected = false;
908 m_isSelected = false;
909 m_delaySelect = false;
910
911 mu = parent_scene.m_materialContactsData[(int)Material.Wood].mu;
912 bounce = parent_scene.m_materialContactsData[(int)Material.Wood].bounce;
913
914 CalcPrimBodyData();
915
916 m_building = true; // control must set this to false when done
917
918 AddChange(changes.Add, null);
919 }
920
921 private void resetCollisionAccounting()
922 {
923 m_collisionscore = 0;
924 }
925
926 private void createAMotor(Vector3 axis)
927 {
928 if (Body == IntPtr.Zero)
929 return;
930
931 if (Amotor != IntPtr.Zero)
932 {
933 d.JointDestroy(Amotor);
934 Amotor = IntPtr.Zero;
935 }
936
937 int axisnum = 3 - (int)(axis.X + axis.Y + axis.Z);
938
939 if (axisnum <= 0)
940 return;
941
942 // stop it
943 d.BodySetTorque(Body, 0, 0, 0);
944 d.BodySetAngularVel(Body, 0, 0, 0);
945
946 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
947 d.JointAttach(Amotor, Body, IntPtr.Zero);
948
949 d.JointSetAMotorMode(Amotor, 0);
950
951 d.JointSetAMotorNumAxes(Amotor, axisnum);
952
953 // get current orientation to lock
954
955 d.Quaternion dcur = d.BodyGetQuaternion(Body);
956 Quaternion curr; // crap convertion between identical things
957 curr.X = dcur.X;
958 curr.Y = dcur.Y;
959 curr.Z = dcur.Z;
960 curr.W = dcur.W;
961 Vector3 ax;
962
963 int i = 0;
964 int j = 0;
965 if (axis.X == 0)
966 {
967 ax = (new Vector3(1, 0, 0)) * curr; // rotate world X to current local X
968 // ODE should do this with axis relative to body 1 but seems to fail
969 d.JointSetAMotorAxis(Amotor, 0, 0, ax.X, ax.Y, ax.Z);
970 d.JointSetAMotorAngle(Amotor, 0, 0);
971 d.JointSetAMotorParam(Amotor, (int)d.JointParam.LoStop, -0.000001f);
972 d.JointSetAMotorParam(Amotor, (int)d.JointParam.HiStop, 0.000001f);
973 d.JointSetAMotorParam(Amotor, (int)d.JointParam.Vel, 0);
974 d.JointSetAMotorParam(Amotor, (int)d.JointParam.FudgeFactor, 0.0001f);
975 d.JointSetAMotorParam(Amotor, (int)d.JointParam.Bounce, 0f);
976 d.JointSetAMotorParam(Amotor, (int)d.JointParam.FMax, 5e8f);
977 d.JointSetAMotorParam(Amotor, (int)d.JointParam.StopCFM, 0f);
978 d.JointSetAMotorParam(Amotor, (int)d.JointParam.StopERP, 0.8f);
979 i++;
980 j = 256; // move to next axis set
981 }
982
983 if (axis.Y == 0)
984 {
985 ax = (new Vector3(0, 1, 0)) * curr;
986 d.JointSetAMotorAxis(Amotor, i, 0, ax.X, ax.Y, ax.Z);
987 d.JointSetAMotorAngle(Amotor, i, 0);
988 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.LoStop, -0.000001f);
989 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.HiStop, 0.000001f);
990 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.Vel, 0);
991 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.FudgeFactor, 0.0001f);
992 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.Bounce, 0f);
993 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.FMax, 5e8f);
994 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.StopCFM, 0f);
995 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.StopERP, 0.8f);
996 i++;
997 j += 256;
998 }
999
1000 if (axis.Z == 0)
1001 {
1002 ax = (new Vector3(0, 0, 1)) * curr;
1003 d.JointSetAMotorAxis(Amotor, i, 0, ax.X, ax.Y, ax.Z);
1004 d.JointSetAMotorAngle(Amotor, i, 0);
1005 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.LoStop, -0.000001f);
1006 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.HiStop, 0.000001f);
1007 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.Vel, 0);
1008 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.FudgeFactor, 0.0001f);
1009 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.Bounce, 0f);
1010 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.FMax, 5e8f);
1011 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.StopCFM, 0f);
1012 d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.StopERP, 0.8f);
1013 }
1014 }
1015
1016 private bool setMesh(OdeScene parent_scene)
1017 {
1018 if (Body != IntPtr.Zero)
1019 {
1020 if (childPrim)
1021 {
1022 if (_parent != null)
1023 {
1024 OdePrim parent = (OdePrim)_parent;
1025 parent.ChildDelink(this, false);
1026 }
1027 }
1028 else
1029 {
1030 DestroyBody();
1031 }
1032 }
1033
1034 IMesh mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, (int)LevelOfDetail.High, true);
1035 if (mesh == null)
1036 {
1037 m_log.WarnFormat("[PHYSICS]: CreateMesh Failed on prim {0} at <{1},{2},{3}>.", Name, _position.X, _position.Y, _position.Z);
1038 return false;
1039 }
1040
1041 IntPtr vertices, indices;
1042 int vertexCount, indexCount;
1043 int vertexStride, triStride;
1044
1045 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
1046 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
1047
1048 if (vertexCount == 0 || indexCount == 0)
1049 {
1050 m_log.WarnFormat("[PHYSICS]: Got invalid mesh on prim {0} at <{1},{2},{3}>. mesh UUID {4}",
1051 Name, _position.X, _position.Y, _position.Z, _pbs.SculptTexture.ToString());
1052 mesh.releaseSourceMeshData();
1053 return false;
1054 }
1055
1056 primOOBoffset = mesh.GetCentroid();
1057 hasOOBoffsetFromMesh = true;
1058
1059 mesh.releaseSourceMeshData();
1060
1061 IntPtr geo = IntPtr.Zero;
1062
1063 try
1064 {
1065 _triMeshData = d.GeomTriMeshDataCreate();
1066
1067 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
1068 d.GeomTriMeshDataPreprocess(_triMeshData);
1069
1070 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1071 geo = d.CreateTriMesh(m_targetSpace, _triMeshData, null, null, null);
1072 }
1073
1074 catch (Exception e)
1075 {
1076 m_log.ErrorFormat("[PHYSICS]: SetGeom Mesh failed for {0} exception: {1}", Name, e);
1077 if (_triMeshData != IntPtr.Zero)
1078 {
1079 d.GeomTriMeshDataDestroy(_triMeshData);
1080 _triMeshData = IntPtr.Zero;
1081 }
1082 return false;
1083 }
1084
1085 SetGeom(geo);
1086 return true;
1087 }
1088
1089 private void SetGeom(IntPtr geom)
1090 {
1091 prim_geom = geom;
1092 //Console.WriteLine("SetGeom to " + prim_geom + " for " + Name);
1093 if (prim_geom != IntPtr.Zero)
1094 {
1095 if (m_NoColide)
1096 {
1097 d.GeomSetCategoryBits(prim_geom, 0);
1098 if (m_isphysical)
1099 {
1100 d.GeomSetCollideBits(prim_geom, (int)CollisionCategories.Land);
1101 }
1102 else
1103 {
1104 d.GeomSetCollideBits(prim_geom, 0);
1105 d.GeomDisable(prim_geom);
1106 }
1107 }
1108 else
1109 {
1110 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1111 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1112 }
1113
1114 CalcPrimBodyData();
1115
1116 _parent_scene.geom_name_map[prim_geom] = Name;
1117 _parent_scene.actor_name_map[prim_geom] = this;
1118
1119 }
1120 else
1121 m_log.Warn("Setting bad Geom");
1122 }
1123
1124
1125 /// <summary>
1126 /// Create a geometry for the given mesh in the given target space.
1127 /// </summary>
1128 /// <param name="m_targetSpace"></param>
1129 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1130 private void CreateGeom()
1131 {
1132 if (_triMeshData != IntPtr.Zero)
1133 {
1134 d.GeomTriMeshDataDestroy(_triMeshData);
1135 _triMeshData = IntPtr.Zero;
1136 }
1137
1138 bool haveMesh = false;
1139 hasOOBoffsetFromMesh = false;
1140 m_NoColide = false;
1141
1142 if (_parent_scene.needsMeshing(_pbs))
1143 {
1144 haveMesh = setMesh(_parent_scene); // this will give a mesh to non trivial known prims
1145 if (!haveMesh)
1146 m_NoColide = true;
1147 }
1148
1149 if (!haveMesh)
1150 {
1151 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1
1152 && _size.X == _size.Y && _size.Y == _size.Z)
1153 { // it's a sphere
1154 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1155 try
1156 {
1157 SetGeom(d.CreateSphere(m_targetSpace, _size.X * 0.5f));
1158 }
1159 catch (Exception e)
1160 {
1161 m_log.WarnFormat("[PHYSICS]: Create sphere failed: {0}", e);
1162 return;
1163 }
1164 }
1165 else
1166 {// do it as a box
1167 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1168 try
1169 {
1170 //Console.WriteLine(" CreateGeom 4");
1171 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1172 }
1173 catch (Exception e)
1174 {
1175 m_log.Warn("[PHYSICS]: Create box failed: {0}", e);
1176 return;
1177 }
1178 }
1179 }
1180 }
1181
1182 /// <summary>
1183 /// Set a new geometry for this prim.
1184 /// </summary>
1185 /// <param name="geom"></param>
1186 private void RemoveGeom()
1187 {
1188 if (prim_geom != IntPtr.Zero)
1189 {
1190 _parent_scene.geom_name_map.Remove(prim_geom);
1191 _parent_scene.actor_name_map.Remove(prim_geom);
1192 try
1193 {
1194 d.GeomDestroy(prim_geom);
1195 if (_triMeshData != IntPtr.Zero)
1196 {
1197 d.GeomTriMeshDataDestroy(_triMeshData);
1198 _triMeshData = IntPtr.Zero;
1199 }
1200 }
1201 // catch (System.AccessViolationException)
1202 catch (Exception e)
1203 {
1204 m_log.ErrorFormat("[PHYSICS]: PrimGeom destruction failed for {0} exception {1}", Name, e);
1205 }
1206
1207 prim_geom = IntPtr.Zero;
1208 }
1209 else
1210 {
1211 m_log.ErrorFormat("[PHYSICS]: PrimGeom destruction BAD {0}", Name);
1212 }
1213 Body = IntPtr.Zero;
1214 hasOOBoffsetFromMesh = false;
1215 CalcPrimBodyData();
1216 }
1217
1218 private void ChildSetGeom(OdePrim odePrim)
1219 {
1220 // well..
1221 DestroyBody();
1222 MakeBody();
1223 }
1224
1225 //sets non physical prim m_targetSpace to right space in spaces grid for static prims
1226 // should only be called for non physical prims unless they are becoming non physical
1227 private void SetInStaticSpace(OdePrim prim)
1228 {
1229 IntPtr targetSpace = _parent_scene.MoveGeomToStaticSpace(prim.prim_geom, prim._position, prim.m_targetSpace);
1230 prim.m_targetSpace = targetSpace;
1231 d.GeomEnable(prim_geom);
1232 }
1233
1234 public void enableBodySoft()
1235 {
1236 if (!childPrim && !m_isSelected)
1237 {
1238 if (m_isphysical && Body != IntPtr.Zero)
1239 {
1240 m_collisionCategories |= CollisionCategories.Body;
1241 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1242
1243 foreach (OdePrim prm in childrenPrim)
1244 {
1245 prm.m_collisionCategories = m_collisionCategories;
1246 prm.m_collisionFlags = m_collisionFlags;
1247
1248 if (prm.prim_geom != IntPtr.Zero)
1249 {
1250 if (prm.m_NoColide)
1251 {
1252 d.GeomSetCategoryBits(prm.prim_geom, 0);
1253 d.GeomSetCollideBits(prm.prim_geom, (int)CollisionCategories.Land);
1254 }
1255 else
1256 {
1257 d.GeomSetCategoryBits(prm.prim_geom, (int)m_collisionCategories);
1258 d.GeomSetCollideBits(prm.prim_geom, (int)m_collisionFlags);
1259 }
1260 d.GeomEnable(prm.prim_geom);
1261 }
1262 }
1263
1264 if (prim_geom != IntPtr.Zero)
1265 {
1266 if (m_NoColide)
1267 {
1268 d.GeomSetCategoryBits(prim_geom, 0);
1269 d.GeomSetCollideBits(prim_geom, (int)CollisionCategories.Land);
1270 }
1271 else
1272 {
1273 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1274 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1275 }
1276 d.GeomEnable(prim_geom);
1277 }
1278 d.BodyEnable(Body);
1279 }
1280 }
1281 m_disabled = false;
1282 resetCollisionAccounting(); // this sets m_disable to false
1283 }
1284
1285 private void disableBodySoft()
1286 {
1287 m_disabled = true;
1288 if (!childPrim)
1289 {
1290 if (m_isphysical && Body != IntPtr.Zero)
1291 {
1292 m_collisionCategories &= ~CollisionCategories.Body;
1293 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1294
1295 foreach (OdePrim prm in childrenPrim)
1296 {
1297 prm.m_collisionCategories = m_collisionCategories;
1298 prm.m_collisionFlags = m_collisionFlags;
1299
1300 if (prm.prim_geom != IntPtr.Zero)
1301 {
1302 if (prm.m_NoColide)
1303 {
1304 d.GeomSetCategoryBits(prm.prim_geom, 0);
1305 d.GeomSetCollideBits(prm.prim_geom, 0);
1306 }
1307 else
1308 {
1309 d.GeomSetCategoryBits(prm.prim_geom, (int)m_collisionCategories);
1310 d.GeomSetCollideBits(prm.prim_geom, (int)m_collisionFlags);
1311 }
1312 d.GeomDisable(prm.prim_geom);
1313 }
1314 }
1315
1316 if (prim_geom != IntPtr.Zero)
1317 {
1318 if (m_NoColide)
1319 {
1320 d.GeomSetCategoryBits(prim_geom, 0);
1321 d.GeomSetCollideBits(prim_geom, 0);
1322 }
1323 else
1324 {
1325 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1326 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1327 }
1328 d.GeomDisable(prim_geom);
1329 }
1330
1331 d.BodyDisable(Body);
1332 }
1333 }
1334 }
1335
1336 private void MakeBody()
1337 {
1338 if (!m_isphysical) // only physical get bodies
1339 return;
1340
1341 if (childPrim) // child prims don't get bodies;
1342 return;
1343
1344 if (m_building)
1345 return;
1346
1347 if (prim_geom == IntPtr.Zero)
1348 {
1349 m_log.Warn("[PHYSICS]: Unable to link the linkset. Root has no geom yet");
1350 return;
1351 }
1352
1353 if (Body != IntPtr.Zero)
1354 {
1355 d.BodyDestroy(Body);
1356 Body = IntPtr.Zero;
1357 m_log.Warn("[PHYSICS]: MakeBody called having a body");
1358 }
1359
1360
1361 if (d.GeomGetBody(prim_geom) != IntPtr.Zero)
1362 {
1363 d.GeomSetBody(prim_geom, IntPtr.Zero);
1364 m_log.Warn("[PHYSICS]: MakeBody root geom already had a body");
1365 }
1366
1367 d.Matrix3 mymat = new d.Matrix3();
1368 d.Quaternion myrot = new d.Quaternion();
1369 d.Mass objdmass = new d.Mass { };
1370
1371 Body = d.BodyCreate(_parent_scene.world);
1372
1373 DMassDup(ref primdMass, out objdmass);
1374
1375 // rotate inertia
1376 myrot.X = _orientation.X;
1377 myrot.Y = _orientation.Y;
1378 myrot.Z = _orientation.Z;
1379 myrot.W = _orientation.W;
1380
1381 d.RfromQ(out mymat, ref myrot);
1382 d.MassRotate(ref objdmass, ref mymat);
1383
1384 // set the body rotation and position
1385 d.BodySetRotation(Body, ref mymat);
1386
1387 // recompute full object inertia if needed
1388 if (childrenPrim.Count > 0)
1389 {
1390 d.Matrix3 mat = new d.Matrix3();
1391 d.Quaternion quat = new d.Quaternion();
1392 d.Mass tmpdmass = new d.Mass { };
1393 Vector3 rcm;
1394
1395 rcm.X = _position.X + objdmass.c.X;
1396 rcm.Y = _position.Y + objdmass.c.Y;
1397 rcm.Z = _position.Z + objdmass.c.Z;
1398
1399 lock (childrenPrim)
1400 {
1401 foreach (OdePrim prm in childrenPrim)
1402 {
1403 if (prm.prim_geom == IntPtr.Zero)
1404 {
1405 m_log.Warn("[PHYSICS]: Unable to link one of the linkset elements, skipping it. No geom yet");
1406 continue;
1407 }
1408
1409 DMassCopy(ref prm.primdMass, ref tmpdmass);
1410
1411 // apply prim current rotation to inertia
1412 quat.X = prm._orientation.X;
1413 quat.Y = prm._orientation.Y;
1414 quat.Z = prm._orientation.Z;
1415 quat.W = prm._orientation.W;
1416 d.RfromQ(out mat, ref quat);
1417 d.MassRotate(ref tmpdmass, ref mat);
1418
1419 Vector3 ppos = prm._position;
1420 ppos.X += tmpdmass.c.X - rcm.X;
1421 ppos.Y += tmpdmass.c.Y - rcm.Y;
1422 ppos.Z += tmpdmass.c.Z - rcm.Z;
1423
1424 // refer inertia to root prim center of mass position
1425 d.MassTranslate(ref tmpdmass,
1426 ppos.X,
1427 ppos.Y,
1428 ppos.Z);
1429
1430 d.MassAdd(ref objdmass, ref tmpdmass); // add to total object inertia
1431 // fix prim colision cats
1432
1433 if (d.GeomGetBody(prm.prim_geom) != IntPtr.Zero)
1434 {
1435 d.GeomSetBody(prm.prim_geom, IntPtr.Zero);
1436 m_log.Warn("[PHYSICS]: MakeBody child geom already had a body");
1437 }
1438
1439 d.GeomClearOffset(prm.prim_geom);
1440 d.GeomSetBody(prm.prim_geom, Body);
1441 prm.Body = Body;
1442 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); // set relative rotation
1443 }
1444 }
1445 }
1446
1447 d.GeomClearOffset(prim_geom); // make sure we don't have a hidden offset
1448 // associate root geom with body
1449 d.GeomSetBody(prim_geom, Body);
1450
1451 d.BodySetPosition(Body, _position.X + objdmass.c.X, _position.Y + objdmass.c.Y, _position.Z + objdmass.c.Z);
1452 d.GeomSetOffsetWorldPosition(prim_geom, _position.X, _position.Y, _position.Z);
1453
1454 d.MassTranslate(ref objdmass, -objdmass.c.X, -objdmass.c.Y, -objdmass.c.Z); // ode wants inertia at center of body
1455 myrot.W = -myrot.W;
1456 d.RfromQ(out mymat, ref myrot);
1457 d.MassRotate(ref objdmass, ref mymat);
1458 d.BodySetMass(Body, ref objdmass);
1459 _mass = objdmass.mass;
1460
1461 // disconnect from world gravity so we can apply buoyancy
1462 d.BodySetGravityMode(Body, false);
1463
1464 d.BodySetAutoDisableFlag(Body, true);
1465 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1466 // d.BodySetLinearDampingThreshold(Body, 0.01f);
1467 // d.BodySetAngularDampingThreshold(Body, 0.001f);
1468 d.BodySetDamping(Body, .002f, .002f);
1469
1470
1471 if (m_targetSpace != IntPtr.Zero)
1472 {
1473 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1474 if (d.SpaceQuery(m_targetSpace, prim_geom))
1475 d.SpaceRemove(m_targetSpace, prim_geom);
1476 }
1477
1478
1479 if (childrenPrim.Count == 0)
1480 {
1481 collide_geom = prim_geom;
1482 m_targetSpace = _parent_scene.ActiveSpace;
1483 d.SpaceAdd(m_targetSpace, prim_geom);
1484 }
1485 else
1486 {
1487 m_targetSpace = d.HashSpaceCreate(_parent_scene.ActiveSpace);
1488 d.HashSpaceSetLevels(m_targetSpace, -2, 8);
1489 d.SpaceSetSublevel(m_targetSpace, 3);
1490 d.SpaceSetCleanup(m_targetSpace, false);
1491 d.SpaceAdd(m_targetSpace, prim_geom);
1492 collide_geom = m_targetSpace;
1493 }
1494
1495 lock (childrenPrim)
1496 {
1497 foreach (OdePrim prm in childrenPrim)
1498 {
1499 if (prm.prim_geom == IntPtr.Zero)
1500 continue;
1501
1502 Vector3 ppos = prm._position;
1503 d.GeomSetOffsetWorldPosition(prm.prim_geom, ppos.X, ppos.Y, ppos.Z); // set relative position
1504
1505 if (prm.m_targetSpace != m_targetSpace)
1506 {
1507 if (prm.m_targetSpace != IntPtr.Zero)
1508 {
1509 _parent_scene.waitForSpaceUnlock(prm.m_targetSpace);
1510 if (d.SpaceQuery(prm.m_targetSpace, prm.prim_geom))
1511 d.SpaceRemove(prm.m_targetSpace, prm.prim_geom);
1512 }
1513 prm.m_targetSpace = m_targetSpace;
1514 d.SpaceAdd(m_targetSpace, prm.prim_geom);
1515 }
1516
1517 if (m_isSelected || m_disabled)
1518 {
1519 prm.m_collisionCategories &= ~CollisionCategories.Body;
1520 prm.m_collisionFlags &= ~(CollisionCategories.Land | CollisionCategories.Wind);
1521 d.GeomDisable(prm.prim_geom);
1522 }
1523 else
1524 {
1525 prm.m_collisionCategories |= CollisionCategories.Body;
1526 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1527 }
1528
1529 if (prm.m_NoColide)
1530 {
1531 d.GeomSetCategoryBits(prm.prim_geom, 0);
1532 d.GeomSetCollideBits(prm.prim_geom, (int)CollisionCategories.Land);
1533 }
1534 else
1535 {
1536 d.GeomSetCategoryBits(prm.prim_geom, (int)m_collisionCategories);
1537 d.GeomSetCollideBits(prm.prim_geom, (int)m_collisionFlags);
1538 }
1539 prm.m_collisionscore = 0;
1540
1541 if(!m_disabled)
1542 prm.m_disabled = false;
1543
1544 _parent_scene.addActivePrim(prm);
1545 }
1546 }
1547
1548 // The body doesn't already have a finite rotation mode set here
1549 if ((!m_angularlock.ApproxEquals(Vector3.One, 0.0f)) && _parent == null)
1550 {
1551 createAMotor(m_angularlock);
1552 }
1553
1554 if (m_isSelected || m_disabled)
1555 {
1556 m_collisionCategories &= ~CollisionCategories.Body;
1557 m_collisionFlags &= ~(CollisionCategories.Land | CollisionCategories.Wind);
1558
1559 d.GeomDisable(prim_geom);
1560 d.BodyDisable(Body);
1561 }
1562 else
1563 {
1564 m_collisionCategories |= CollisionCategories.Body;
1565 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1566
1567 d.BodySetAngularVel(Body, m_rotationalVelocity.X, m_rotationalVelocity.Y, m_rotationalVelocity.Z);
1568 d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
1569 }
1570
1571 if (m_NoColide)
1572 {
1573 d.GeomSetCategoryBits(prim_geom, 0);
1574 d.GeomSetCollideBits(prim_geom, (int)CollisionCategories.Land);
1575 }
1576 else
1577 {
1578 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1579 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1580 }
1581
1582 m_collisionscore = 0;
1583
1584 m_softcolide = true;
1585 _parent_scene.addActivePrim(this);
1586 _parent_scene.addActiveGroups(this);
1587 }
1588
1589 private void DestroyBody()
1590 {
1591 if (Body != IntPtr.Zero)
1592 {
1593 _parent_scene.remActivePrim(this);
1594 m_collisionCategories &= ~CollisionCategories.Body;
1595 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1596 if (prim_geom != IntPtr.Zero)
1597 {
1598 if (m_NoColide)
1599 {
1600 d.GeomSetCategoryBits(prim_geom, 0);
1601 d.GeomSetCollideBits(prim_geom, 0);
1602 }
1603 else
1604 {
1605 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1606 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1607 }
1608 UpdateDataFromGeom();
1609 d.GeomSetBody(prim_geom, IntPtr.Zero);
1610 SetInStaticSpace(this);
1611 }
1612
1613 if (!childPrim)
1614 {
1615 lock (childrenPrim)
1616 {
1617 foreach (OdePrim prm in childrenPrim)
1618 {
1619 _parent_scene.remActivePrim(prm);
1620 prm.m_collisionCategories = m_collisionCategories;
1621 prm.m_collisionFlags = m_collisionFlags;
1622 if (prm.prim_geom != IntPtr.Zero)
1623 {
1624 if (prm.m_NoColide)
1625 {
1626 d.GeomSetCategoryBits(prm.prim_geom, 0);
1627 d.GeomSetCollideBits(prm.prim_geom, 0);
1628 }
1629 else
1630 {
1631 d.GeomSetCategoryBits(prm.prim_geom, (int)m_collisionCategories);
1632 d.GeomSetCollideBits(prm.prim_geom, (int)m_collisionFlags);
1633 }
1634 prm.UpdateDataFromGeom();
1635 SetInStaticSpace(prm);
1636 }
1637 prm.Body = IntPtr.Zero;
1638 prm._mass = prm.primMass;
1639 prm.m_collisionscore = 0;
1640 }
1641 }
1642 if (Amotor != IntPtr.Zero)
1643 {
1644 d.JointDestroy(Amotor);
1645 Amotor = IntPtr.Zero;
1646 }
1647 _parent_scene.remActiveGroup(this);
1648 d.BodyDestroy(Body);
1649 }
1650 Body = IntPtr.Zero;
1651 }
1652 _mass = primMass;
1653 m_collisionscore = 0;
1654 }
1655
1656 #region Mass Calculation
1657
1658 private float CalculatePrimVolume()
1659 {
1660 float volume = _size.X * _size.Y * _size.Z; // default
1661 float tmp;
1662
1663 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
1664 float hollowVolume = hollowAmount * hollowAmount;
1665
1666 switch (_pbs.ProfileShape)
1667 {
1668 case ProfileShape.Square:
1669 // default box
1670
1671 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1672 {
1673 if (hollowAmount > 0.0)
1674 {
1675 switch (_pbs.HollowShape)
1676 {
1677 case HollowShape.Square:
1678 case HollowShape.Same:
1679 break;
1680
1681 case HollowShape.Circle:
1682
1683 hollowVolume *= 0.78539816339f;
1684 break;
1685
1686 case HollowShape.Triangle:
1687
1688 hollowVolume *= (0.5f * .5f);
1689 break;
1690
1691 default:
1692 hollowVolume = 0;
1693 break;
1694 }
1695 volume *= (1.0f - hollowVolume);
1696 }
1697 }
1698
1699 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1700 {
1701 //a tube
1702
1703 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
1704 tmp = 1.0f - 2.0e-2f * (float)(200 - _pbs.PathScaleY);
1705 volume -= volume * tmp * tmp;
1706
1707 if (hollowAmount > 0.0)
1708 {
1709 hollowVolume *= hollowAmount;
1710
1711 switch (_pbs.HollowShape)
1712 {
1713 case HollowShape.Square:
1714 case HollowShape.Same:
1715 break;
1716
1717 case HollowShape.Circle:
1718 hollowVolume *= 0.78539816339f;
1719 break;
1720
1721 case HollowShape.Triangle:
1722 hollowVolume *= 0.5f * 0.5f;
1723 break;
1724 default:
1725 hollowVolume = 0;
1726 break;
1727 }
1728 volume *= (1.0f - hollowVolume);
1729 }
1730 }
1731
1732 break;
1733
1734 case ProfileShape.Circle:
1735
1736 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1737 {
1738 volume *= 0.78539816339f; // elipse base
1739
1740 if (hollowAmount > 0.0)
1741 {
1742 switch (_pbs.HollowShape)
1743 {
1744 case HollowShape.Same:
1745 case HollowShape.Circle:
1746 break;
1747
1748 case HollowShape.Square:
1749 hollowVolume *= 0.5f * 2.5984480504799f;
1750 break;
1751
1752 case HollowShape.Triangle:
1753 hollowVolume *= .5f * 1.27323954473516f;
1754 break;
1755
1756 default:
1757 hollowVolume = 0;
1758 break;
1759 }
1760 volume *= (1.0f - hollowVolume);
1761 }
1762 }
1763
1764 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1765 {
1766 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
1767 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1768 volume *= (1.0f - tmp * tmp);
1769
1770 if (hollowAmount > 0.0)
1771 {
1772
1773 // calculate the hollow volume by it's shape compared to the prim shape
1774 hollowVolume *= hollowAmount;
1775
1776 switch (_pbs.HollowShape)
1777 {
1778 case HollowShape.Same:
1779 case HollowShape.Circle:
1780 break;
1781
1782 case HollowShape.Square:
1783 hollowVolume *= 0.5f * 2.5984480504799f;
1784 break;
1785
1786 case HollowShape.Triangle:
1787 hollowVolume *= .5f * 1.27323954473516f;
1788 break;
1789
1790 default:
1791 hollowVolume = 0;
1792 break;
1793 }
1794 volume *= (1.0f - hollowVolume);
1795 }
1796 }
1797 break;
1798
1799 case ProfileShape.HalfCircle:
1800 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1801 {
1802 volume *= 0.52359877559829887307710723054658f;
1803 }
1804 break;
1805
1806 case ProfileShape.EquilateralTriangle:
1807
1808 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1809 {
1810 volume *= 0.32475953f;
1811
1812 if (hollowAmount > 0.0)
1813 {
1814
1815 // calculate the hollow volume by it's shape compared to the prim shape
1816 switch (_pbs.HollowShape)
1817 {
1818 case HollowShape.Same:
1819 case HollowShape.Triangle:
1820 hollowVolume *= .25f;
1821 break;
1822
1823 case HollowShape.Square:
1824 hollowVolume *= 0.499849f * 3.07920140172638f;
1825 break;
1826
1827 case HollowShape.Circle:
1828 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1829 // Cyllinder hollow volume calculation
1830
1831 hollowVolume *= 0.1963495f * 3.07920140172638f;
1832 break;
1833
1834 default:
1835 hollowVolume = 0;
1836 break;
1837 }
1838 volume *= (1.0f - hollowVolume);
1839 }
1840 }
1841 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1842 {
1843 volume *= 0.32475953f;
1844 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
1845 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1846 volume *= (1.0f - tmp * tmp);
1847
1848 if (hollowAmount > 0.0)
1849 {
1850
1851 hollowVolume *= hollowAmount;
1852
1853 switch (_pbs.HollowShape)
1854 {
1855 case HollowShape.Same:
1856 case HollowShape.Triangle:
1857 hollowVolume *= .25f;
1858 break;
1859
1860 case HollowShape.Square:
1861 hollowVolume *= 0.499849f * 3.07920140172638f;
1862 break;
1863
1864 case HollowShape.Circle:
1865
1866 hollowVolume *= 0.1963495f * 3.07920140172638f;
1867 break;
1868
1869 default:
1870 hollowVolume = 0;
1871 break;
1872 }
1873 volume *= (1.0f - hollowVolume);
1874 }
1875 }
1876 break;
1877
1878 default:
1879 break;
1880 }
1881
1882 float taperX1;
1883 float taperY1;
1884 float taperX;
1885 float taperY;
1886 float pathBegin;
1887 float pathEnd;
1888 float profileBegin;
1889 float profileEnd;
1890
1891 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
1892 {
1893 taperX1 = _pbs.PathScaleX * 0.01f;
1894 if (taperX1 > 1.0f)
1895 taperX1 = 2.0f - taperX1;
1896 taperX = 1.0f - taperX1;
1897
1898 taperY1 = _pbs.PathScaleY * 0.01f;
1899 if (taperY1 > 1.0f)
1900 taperY1 = 2.0f - taperY1;
1901 taperY = 1.0f - taperY1;
1902 }
1903 else
1904 {
1905 taperX = _pbs.PathTaperX * 0.01f;
1906 if (taperX < 0.0f)
1907 taperX = -taperX;
1908 taperX1 = 1.0f - taperX;
1909
1910 taperY = _pbs.PathTaperY * 0.01f;
1911 if (taperY < 0.0f)
1912 taperY = -taperY;
1913 taperY1 = 1.0f - taperY;
1914 }
1915
1916 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1917
1918 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
1919 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
1920 volume *= (pathEnd - pathBegin);
1921
1922 // this is crude aproximation
1923 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
1924 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
1925 volume *= (profileEnd - profileBegin);
1926
1927 return volume;
1928 }
1929
1930
1931 private void CalcPrimBodyData()
1932 {
1933 float volume;
1934
1935 if (prim_geom == IntPtr.Zero)
1936 {
1937 // Ubit let's have a initial basic OOB
1938 primOOBsize.X = _size.X;
1939 primOOBsize.Y = _size.Y;
1940 primOOBsize.Z = _size.Z;
1941 primOOBoffset = Vector3.Zero;
1942 }
1943 else
1944 {
1945 d.AABB AABB;
1946 d.GeomGetAABB(prim_geom, out AABB); // get the AABB from engine geom
1947
1948 primOOBsize.X = (AABB.MaxX - AABB.MinX);
1949 primOOBsize.Y = (AABB.MaxY - AABB.MinY);
1950 primOOBsize.Z = (AABB.MaxZ - AABB.MinZ);
1951 if (!hasOOBoffsetFromMesh)
1952 {
1953 primOOBoffset.X = (AABB.MaxX + AABB.MinX) * 0.5f;
1954 primOOBoffset.Y = (AABB.MaxY + AABB.MinY) * 0.5f;
1955 primOOBoffset.Z = (AABB.MaxZ + AABB.MinZ) * 0.5f;
1956 }
1957 }
1958
1959 // also its own inertia and mass
1960 // keep using basic shape mass for now
1961 volume = CalculatePrimVolume();
1962
1963 primMass = m_density * volume;
1964
1965 if (primMass <= 0)
1966 primMass = 0.0001f;//ckrinke: Mass must be greater then zero.
1967 if (primMass > _parent_scene.maximumMassObject)
1968 primMass = _parent_scene.maximumMassObject;
1969
1970 _mass = primMass; // just in case
1971
1972 d.MassSetBoxTotal(out primdMass, primMass, primOOBsize.X, primOOBsize.Y, primOOBsize.Z);
1973
1974 d.MassTranslate(ref primdMass,
1975 primOOBoffset.X,
1976 primOOBoffset.Y,
1977 primOOBoffset.Z);
1978
1979 primOOBsize *= 0.5f; // let obb size be a corner coords
1980 primOOBradiusSQ = primOOBsize.LengthSquared();
1981 }
1982
1983
1984 #endregion
1985
1986
1987 /// <summary>
1988 /// Add a child prim to this parent prim.
1989 /// </summary>
1990 /// <param name="prim">Child prim</param>
1991 // I'm the parent
1992 // prim is the child
1993 public void ParentPrim(OdePrim prim)
1994 {
1995 //Console.WriteLine("ParentPrim " + m_primName);
1996 if (this.m_localID != prim.m_localID)
1997 {
1998 DestroyBody(); // for now we need to rebuil entire object on link change
1999
2000 lock (childrenPrim)
2001 {
2002 // adopt the prim
2003 if (!childrenPrim.Contains(prim))
2004 childrenPrim.Add(prim);
2005
2006 // see if this prim has kids and adopt them also
2007 // should not happen for now
2008 foreach (OdePrim prm in prim.childrenPrim)
2009 {
2010 if (!childrenPrim.Contains(prm))
2011 {
2012 if (prm.Body != IntPtr.Zero)
2013 {
2014 if (prm.prim_geom != IntPtr.Zero)
2015 d.GeomSetBody(prm.prim_geom, IntPtr.Zero);
2016 if (prm.Body != prim.Body)
2017 prm.DestroyBody(); // don't loose bodies around
2018 prm.Body = IntPtr.Zero;
2019 }
2020
2021 childrenPrim.Add(prm);
2022 prm._parent = this;
2023 }
2024 }
2025 }
2026 //Remove old children from the prim
2027 prim.childrenPrim.Clear();
2028
2029 if (prim.Body != IntPtr.Zero)
2030 {
2031 if (prim.prim_geom != IntPtr.Zero)
2032 d.GeomSetBody(prim.prim_geom, IntPtr.Zero);
2033 prim.DestroyBody(); // don't loose bodies around
2034 prim.Body = IntPtr.Zero;
2035 }
2036
2037 prim.childPrim = true;
2038 prim._parent = this;
2039
2040 MakeBody(); // full nasty reconstruction
2041 }
2042 }
2043
2044 private void UpdateChildsfromgeom()
2045 {
2046 if (childrenPrim.Count > 0)
2047 {
2048 foreach (OdePrim prm in childrenPrim)
2049 prm.UpdateDataFromGeom();
2050 }
2051 }
2052
2053 private void UpdateDataFromGeom()
2054 {
2055 if (prim_geom != IntPtr.Zero)
2056 {
2057 d.Vector3 lpos;
2058 d.GeomCopyPosition(prim_geom, out lpos);
2059 _position.X = lpos.X;
2060 _position.Y = lpos.Y;
2061 _position.Z = lpos.Z;
2062 d.Quaternion qtmp = new d.Quaternion { };
2063 d.GeomCopyQuaternion(prim_geom, out qtmp);
2064 _orientation.W = qtmp.W;
2065 _orientation.X = qtmp.X;
2066 _orientation.Y = qtmp.Y;
2067 _orientation.Z = qtmp.Z;
2068 }
2069 }
2070
2071 private void ChildDelink(OdePrim odePrim, bool remakebodies)
2072 {
2073 // Okay, we have a delinked child.. destroy all body and remake
2074 if (odePrim != this && !childrenPrim.Contains(odePrim))
2075 return;
2076
2077 DestroyBody();
2078
2079 if (odePrim == this) // delinking the root prim
2080 {
2081 OdePrim newroot = null;
2082 lock (childrenPrim)
2083 {
2084 if (childrenPrim.Count > 0)
2085 {
2086 newroot = childrenPrim[0];
2087 childrenPrim.RemoveAt(0);
2088 foreach (OdePrim prm in childrenPrim)
2089 {
2090 newroot.childrenPrim.Add(prm);
2091 }
2092 childrenPrim.Clear();
2093 }
2094 if (newroot != null)
2095 {
2096 newroot.childPrim = false;
2097 newroot._parent = null;
2098 if (remakebodies)
2099 newroot.MakeBody();
2100 }
2101 }
2102 }
2103
2104 else
2105 {
2106 lock (childrenPrim)
2107 {
2108 childrenPrim.Remove(odePrim);
2109 odePrim.childPrim = false;
2110 odePrim._parent = null;
2111 // odePrim.UpdateDataFromGeom();
2112 if (remakebodies)
2113 odePrim.MakeBody();
2114 }
2115 }
2116 if (remakebodies)
2117 MakeBody();
2118 }
2119
2120 protected void ChildRemove(OdePrim odePrim, bool reMakeBody)
2121 {
2122 // Okay, we have a delinked child.. destroy all body and remake
2123 if (odePrim != this && !childrenPrim.Contains(odePrim))
2124 return;
2125
2126 DestroyBody();
2127
2128 if (odePrim == this)
2129 {
2130 OdePrim newroot = null;
2131 lock (childrenPrim)
2132 {
2133 if (childrenPrim.Count > 0)
2134 {
2135 newroot = childrenPrim[0];
2136 childrenPrim.RemoveAt(0);
2137 foreach (OdePrim prm in childrenPrim)
2138 {
2139 newroot.childrenPrim.Add(prm);
2140 }
2141 childrenPrim.Clear();
2142 }
2143 if (newroot != null)
2144 {
2145 newroot.childPrim = false;
2146 newroot._parent = null;
2147 newroot.MakeBody();
2148 }
2149 }
2150 if (reMakeBody)
2151 MakeBody();
2152 return;
2153 }
2154 else
2155 {
2156 lock (childrenPrim)
2157 {
2158 childrenPrim.Remove(odePrim);
2159 odePrim.childPrim = false;
2160 odePrim._parent = null;
2161 if (reMakeBody)
2162 odePrim.MakeBody();
2163 }
2164 }
2165 MakeBody();
2166 }
2167
2168 #region changes
2169
2170 private void changeadd()
2171 {
2172 CreateGeom();
2173
2174 if (prim_geom != IntPtr.Zero)
2175 {
2176 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2177 d.Quaternion myrot = new d.Quaternion();
2178 myrot.X = _orientation.X;
2179 myrot.Y = _orientation.Y;
2180 myrot.Z = _orientation.Z;
2181 myrot.W = _orientation.W;
2182 d.GeomSetQuaternion(prim_geom, ref myrot);
2183
2184 if (!m_isphysical)
2185 SetInStaticSpace(this);
2186 }
2187
2188 if (m_isphysical && Body == IntPtr.Zero)
2189 {
2190 MakeBody();
2191 }
2192 }
2193
2194 private void changeAngularLock(Vector3 newLock)
2195 {
2196 // do we have a Physical object?
2197 if (Body != IntPtr.Zero)
2198 {
2199 //Check that we have a Parent
2200 //If we have a parent then we're not authorative here
2201 if (_parent == null)
2202 {
2203 if (!newLock.ApproxEquals(Vector3.One, 0f))
2204 {
2205 createAMotor(newLock);
2206 }
2207 else
2208 {
2209 if (Amotor != IntPtr.Zero)
2210 {
2211 d.JointDestroy(Amotor);
2212 Amotor = IntPtr.Zero;
2213 }
2214 }
2215 }
2216 }
2217 // Store this for later in case we get turned into a separate body
2218 m_angularlock = newLock;
2219 }
2220
2221 private void changeLink(OdePrim NewParent)
2222 {
2223 if (_parent == null && NewParent != null)
2224 {
2225 NewParent.ParentPrim(this);
2226 }
2227 else if (_parent != null)
2228 {
2229 if (_parent is OdePrim)
2230 {
2231 if (NewParent != _parent)
2232 {
2233 (_parent as OdePrim).ChildDelink(this, false); // for now...
2234 childPrim = false;
2235
2236 if (NewParent != null)
2237 {
2238 NewParent.ParentPrim(this);
2239 }
2240 }
2241 }
2242 }
2243 _parent = NewParent;
2244 }
2245
2246
2247 private void Stop()
2248 {
2249 if (!childPrim)
2250 {
2251 m_force = Vector3.Zero;
2252 m_forceacc = Vector3.Zero;
2253 m_angularForceacc = Vector3.Zero;
2254 _torque = Vector3.Zero;
2255 _velocity = Vector3.Zero;
2256 _acceleration = Vector3.Zero;
2257 m_rotationalVelocity = Vector3.Zero;
2258 _target_velocity = Vector3.Zero;
2259 if (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE)
2260 m_vehicle.Stop();
2261 }
2262
2263 if (Body != IntPtr.Zero)
2264 {
2265 d.BodySetForce(Body, 0f, 0f, 0f);
2266 d.BodySetTorque(Body, 0f, 0f, 0f);
2267 d.BodySetLinearVel(Body, 0f, 0f, 0f);
2268 d.BodySetAngularVel(Body, 0f, 0f, 0f);
2269 }
2270 }
2271
2272 private void changeSelectedStatus(bool newval)
2273 {
2274 if (m_lastdoneSelected == newval)
2275 return;
2276
2277 m_lastdoneSelected = newval;
2278 DoSelectedStatus(newval);
2279 }
2280
2281 private void CheckDelaySelect()
2282 {
2283 if (m_delaySelect)
2284 {
2285 DoSelectedStatus(m_isSelected);
2286 }
2287 }
2288
2289 private void DoSelectedStatus(bool newval)
2290 {
2291 m_isSelected = newval;
2292 Stop();
2293
2294 if (newval)
2295 {
2296 if (!childPrim && Body != IntPtr.Zero)
2297 d.BodyDisable(Body);
2298
2299 if (m_delaySelect || m_isphysical)
2300 {
2301 m_collisionCategories = CollisionCategories.Selected;
2302 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
2303
2304 if (!childPrim)
2305 {
2306 foreach (OdePrim prm in childrenPrim)
2307 {
2308 prm.m_collisionCategories = m_collisionCategories;
2309 prm.m_collisionFlags = m_collisionFlags;
2310
2311 if (prm.prim_geom != null)
2312 {
2313
2314 if (prm.m_NoColide)
2315 {
2316 d.GeomSetCategoryBits(prm.prim_geom, 0);
2317 d.GeomSetCollideBits(prm.prim_geom, 0);
2318 }
2319 else
2320 {
2321 d.GeomSetCategoryBits(prm.prim_geom, (int)m_collisionCategories);
2322 d.GeomSetCollideBits(prm.prim_geom, (int)m_collisionFlags);
2323 }
2324 d.GeomDisable(prm.prim_geom);
2325 }
2326 prm.m_delaySelect = false;
2327 }
2328 }
2329
2330 if (prim_geom != null)
2331 {
2332 if (m_NoColide)
2333 {
2334 d.GeomSetCategoryBits(prim_geom, 0);
2335 d.GeomSetCollideBits(prim_geom, 0);
2336 }
2337 else
2338 {
2339 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
2340 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2341 }
2342 d.GeomDisable(prim_geom);
2343 }
2344
2345 m_delaySelect = false;
2346 }
2347 else
2348 {
2349 m_delaySelect = true;
2350 }
2351 }
2352 else
2353 {
2354 if (!childPrim && Body != IntPtr.Zero && !m_disabled)
2355 d.BodyEnable(Body);
2356
2357 m_collisionCategories = CollisionCategories.Geom;
2358 if (m_isphysical)
2359 m_collisionCategories |= CollisionCategories.Body;
2360
2361 m_collisionFlags = m_default_collisionFlags | CollisionCategories.Land;
2362
2363 if (m_collidesWater)
2364 m_collisionFlags |= CollisionCategories.Water;
2365
2366 if (!childPrim)
2367 {
2368 foreach (OdePrim prm in childrenPrim)
2369 {
2370 prm.m_collisionCategories = m_collisionCategories;
2371 prm.m_collisionFlags = m_collisionFlags;
2372
2373 if (!prm.m_disabled && prm.prim_geom != IntPtr.Zero)
2374 {
2375 if (prm.m_NoColide)
2376 {
2377 d.GeomSetCategoryBits(prm.prim_geom, 0);
2378 if (m_isphysical)
2379 d.GeomSetCollideBits(prm.prim_geom, (int)CollisionCategories.Land);
2380 else
2381 d.GeomSetCollideBits(prm.prim_geom, 0);
2382 }
2383 else
2384 {
2385 d.GeomSetCategoryBits(prm.prim_geom, (int)m_collisionCategories);
2386 d.GeomSetCollideBits(prm.prim_geom, (int)m_collisionFlags);
2387 }
2388 d.GeomEnable(prm.prim_geom);
2389 }
2390 prm.m_delaySelect = false;
2391 prm.m_softcolide = true;
2392 }
2393 }
2394
2395 if (!m_disabled && prim_geom != IntPtr.Zero)
2396 {
2397 if (m_NoColide)
2398 {
2399 d.GeomSetCategoryBits(prim_geom, 0);
2400 if (m_isphysical)
2401 d.GeomSetCollideBits(prim_geom, (int)CollisionCategories.Land);
2402 else
2403 d.GeomSetCollideBits(prim_geom, 0);
2404 }
2405 else
2406 {
2407 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
2408 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2409 }
2410 d.GeomEnable(prim_geom);
2411 }
2412
2413 m_delaySelect = false;
2414 m_softcolide = true;
2415 }
2416
2417 resetCollisionAccounting();
2418 }
2419
2420 private void changePosition(Vector3 newPos)
2421 {
2422 CheckDelaySelect();
2423 if (m_isphysical)
2424 {
2425 if (childPrim) // inertia is messed, must rebuild
2426 {
2427 if (m_building)
2428 {
2429 _position = newPos;
2430 }
2431 }
2432 else
2433 {
2434 if (_position != newPos)
2435 {
2436 d.GeomSetPosition(prim_geom, newPos.X, newPos.Y, newPos.Z);
2437 _position = newPos;
2438 }
2439 if (Body != IntPtr.Zero && !d.BodyIsEnabled(Body))
2440 d.BodyEnable(Body);
2441 }
2442 }
2443 else
2444 {
2445 if (prim_geom != IntPtr.Zero)
2446 {
2447 if (newPos != _position)
2448 {
2449 d.GeomSetPosition(prim_geom, newPos.X, newPos.Y, newPos.Z);
2450 _position = newPos;
2451
2452 m_targetSpace = _parent_scene.MoveGeomToStaticSpace(prim_geom, _position, m_targetSpace);
2453 }
2454 }
2455 }
2456 givefakepos--;
2457 if (givefakepos < 0)
2458 givefakepos = 0;
2459 // changeSelectedStatus();
2460 m_softcolide = true;
2461 resetCollisionAccounting();
2462 }
2463
2464 private void changeOrientation(Quaternion newOri)
2465 {
2466 CheckDelaySelect();
2467 if (m_isphysical)
2468 {
2469 if (childPrim) // inertia is messed, must rebuild
2470 {
2471 if (m_building)
2472 {
2473 _orientation = newOri;
2474 }
2475 }
2476 else
2477 {
2478 if (newOri != _orientation)
2479 {
2480 d.Quaternion myrot = new d.Quaternion();
2481 myrot.X = newOri.X;
2482 myrot.Y = newOri.Y;
2483 myrot.Z = newOri.Z;
2484 myrot.W = newOri.W;
2485 d.GeomSetQuaternion(prim_geom, ref myrot);
2486 _orientation = newOri;
2487 if (Body != IntPtr.Zero && !m_angularlock.ApproxEquals(Vector3.One, 0f))
2488 createAMotor(m_angularlock);
2489 }
2490 if (Body != IntPtr.Zero && !d.BodyIsEnabled(Body))
2491 d.BodyEnable(Body);
2492 }
2493 }
2494 else
2495 {
2496 if (prim_geom != IntPtr.Zero)
2497 {
2498 if (newOri != _orientation)
2499 {
2500 d.Quaternion myrot = new d.Quaternion();
2501 myrot.X = newOri.X;
2502 myrot.Y = newOri.Y;
2503 myrot.Z = newOri.Z;
2504 myrot.W = newOri.W;
2505 d.GeomSetQuaternion(prim_geom, ref myrot);
2506 _orientation = newOri;
2507 }
2508 }
2509 }
2510 givefakeori--;
2511 if (givefakeori < 0)
2512 givefakeori = 0;
2513 m_softcolide = true;
2514 resetCollisionAccounting();
2515 }
2516
2517 private void changePositionAndOrientation(Vector3 newPos, Quaternion newOri)
2518 {
2519 CheckDelaySelect();
2520 if (m_isphysical)
2521 {
2522 if (childPrim && m_building) // inertia is messed, must rebuild
2523 {
2524 _position = newPos;
2525 _orientation = newOri;
2526 }
2527 else
2528 {
2529 if (newOri != _orientation)
2530 {
2531 d.Quaternion myrot = new d.Quaternion();
2532 myrot.X = newOri.X;
2533 myrot.Y = newOri.Y;
2534 myrot.Z = newOri.Z;
2535 myrot.W = newOri.W;
2536 d.GeomSetQuaternion(prim_geom, ref myrot);
2537 _orientation = newOri;
2538 if (Body != IntPtr.Zero && !m_angularlock.ApproxEquals(Vector3.One, 0f))
2539 createAMotor(m_angularlock);
2540 }
2541 if (_position != newPos)
2542 {
2543 d.GeomSetPosition(prim_geom, newPos.X, newPos.Y, newPos.Z);
2544 _position = newPos;
2545 }
2546 if (Body != IntPtr.Zero && !d.BodyIsEnabled(Body))
2547 d.BodyEnable(Body);
2548 }
2549 }
2550 else
2551 {
2552 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
2553 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
2554
2555 if (prim_geom != IntPtr.Zero)
2556 {
2557 if (newOri != _orientation)
2558 {
2559 d.Quaternion myrot = new d.Quaternion();
2560 myrot.X = newOri.X;
2561 myrot.Y = newOri.Y;
2562 myrot.Z = newOri.Z;
2563 myrot.W = newOri.W;
2564 d.GeomSetQuaternion(prim_geom, ref myrot);
2565 _orientation = newOri;
2566 }
2567
2568 if (newPos != _position)
2569 {
2570 d.GeomSetPosition(prim_geom, newPos.X, newPos.Y, newPos.Z);
2571 _position = newPos;
2572
2573 m_targetSpace = _parent_scene.MoveGeomToStaticSpace(prim_geom, _position, m_targetSpace);
2574 }
2575 }
2576 }
2577 givefakepos--;
2578 if (givefakepos < 0)
2579 givefakepos = 0;
2580 givefakeori--;
2581 if (givefakeori < 0)
2582 givefakeori = 0;
2583
2584 m_softcolide = true;
2585 resetCollisionAccounting();
2586 }
2587
2588
2589 private void changeDisable(bool disable)
2590 {
2591 if (disable)
2592 {
2593 if (!m_disabled)
2594 disableBodySoft();
2595 }
2596 else
2597 {
2598 if (m_disabled)
2599 enableBodySoft();
2600 }
2601 }
2602
2603 private void changePhysicsStatus(bool NewStatus)
2604 {
2605 CheckDelaySelect();
2606
2607 m_isphysical = NewStatus;
2608
2609 if (!childPrim)
2610 {
2611 if (NewStatus)
2612 {
2613 if (Body == IntPtr.Zero)
2614 {
2615 /*
2616 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2617 {
2618 changeShape(_pbs);
2619 }
2620 else
2621 */
2622 {
2623 MakeBody();
2624 }
2625 }
2626 }
2627 else
2628 {
2629 if (Body != IntPtr.Zero)
2630 {
2631 // UpdateChildsfromgeom();
2632 /* if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2633 {
2634 changeShape(_pbs);
2635 }
2636 else
2637 */
2638 DestroyBody();
2639 }
2640 Stop();
2641 }
2642 }
2643
2644 resetCollisionAccounting();
2645 }
2646
2647 private void changeprimsizeshape()
2648 {
2649 CheckDelaySelect();
2650
2651 OdePrim parent = (OdePrim)_parent;
2652
2653 bool chp = childPrim;
2654
2655 if (chp)
2656 {
2657 if (parent != null)
2658 {
2659 parent.DestroyBody();
2660 }
2661 }
2662 else
2663 {
2664 DestroyBody();
2665 }
2666
2667 RemoveGeom();
2668
2669 // we don't need to do space calculation because the client sends a position update also.
2670 if (_size.X <= 0)
2671 _size.X = 0.01f;
2672 if (_size.Y <= 0)
2673 _size.Y = 0.01f;
2674 if (_size.Z <= 0)
2675 _size.Z = 0.01f;
2676 // Construction of new prim
2677
2678 CreateGeom();
2679
2680 if (prim_geom != IntPtr.Zero)
2681 {
2682 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2683 d.Quaternion myrot = new d.Quaternion();
2684 myrot.X = _orientation.X;
2685 myrot.Y = _orientation.Y;
2686 myrot.Z = _orientation.Z;
2687 myrot.W = _orientation.W;
2688 d.GeomSetQuaternion(prim_geom, ref myrot);
2689 }
2690
2691 if (chp)
2692 {
2693 if (parent != null)
2694 {
2695 parent.MakeBody();
2696 }
2697 }
2698 else
2699 MakeBody();
2700
2701 m_softcolide = true;
2702 resetCollisionAccounting();
2703 }
2704
2705 private void changeSize(Vector3 newSize)
2706 {
2707 _size = newSize;
2708 changeprimsizeshape();
2709 }
2710
2711 private void changeShape(PrimitiveBaseShape newShape)
2712 {
2713 _pbs = newShape;
2714 changeprimsizeshape();
2715 }
2716
2717 private void changeFloatOnWater(bool newval)
2718 {
2719 m_collidesWater = newval;
2720
2721 if (prim_geom != IntPtr.Zero)
2722 {
2723 if (m_collidesWater)
2724 {
2725 m_collisionFlags |= CollisionCategories.Water;
2726 }
2727 else
2728 {
2729 m_collisionFlags &= ~CollisionCategories.Water;
2730 }
2731 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2732 }
2733 }
2734
2735 private void changeSetTorque(Vector3 newtorque)
2736 {
2737 if (!m_isSelected)
2738 {
2739 if (m_isphysical && Body != IntPtr.Zero)
2740 {
2741 if (m_disabled)
2742 enableBodySoft();
2743 else if (!d.BodyIsEnabled(Body))
2744 d.BodyEnable(Body);
2745
2746 }
2747 _torque = newtorque;
2748 }
2749 }
2750
2751 private void changeForce(Vector3 force)
2752 {
2753 m_force = force;
2754 if (Body != IntPtr.Zero && !d.BodyIsEnabled(Body))
2755 d.BodyEnable(Body);
2756 }
2757
2758 private void changeAddForce(Vector3 force)
2759 {
2760 m_forceacc += force;
2761 if (!m_isSelected)
2762 {
2763 lock (this)
2764 {
2765 //m_log.Info("[PHYSICS]: dequeing forcelist");
2766 if (m_isphysical && Body != IntPtr.Zero)
2767 {
2768 if (m_disabled)
2769 enableBodySoft();
2770 else if (!d.BodyIsEnabled(Body))
2771 d.BodyEnable(Body);
2772 }
2773 }
2774
2775 m_collisionscore = 0;
2776 }
2777 }
2778
2779 private void changeAddAngularForce(Vector3 aforce)
2780 {
2781 m_angularForceacc += aforce;
2782 if (!m_isSelected)
2783 {
2784 lock (this)
2785 {
2786 if (m_isphysical && Body != IntPtr.Zero)
2787 {
2788 if (m_disabled)
2789 enableBodySoft();
2790 else if (!d.BodyIsEnabled(Body))
2791 d.BodyEnable(Body);
2792 }
2793 }
2794 m_collisionscore = 0;
2795 }
2796 }
2797
2798 private void changevelocity(Vector3 newVel)
2799 {
2800 if (!m_isSelected)
2801 {
2802 if (Body != IntPtr.Zero)
2803 {
2804 if (m_disabled)
2805 enableBodySoft();
2806 else if (!d.BodyIsEnabled(Body))
2807 d.BodyEnable(Body);
2808
2809 d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z);
2810 }
2811 //resetCollisionAccounting();
2812 }
2813 _velocity = newVel;
2814 }
2815
2816 private void changeVolumedetetion(bool newVolDtc)
2817 {
2818 m_isVolumeDetect = newVolDtc;
2819 }
2820
2821 protected void changeBuilding(bool newbuilding)
2822 {
2823 if ((bool)newbuilding)
2824 {
2825 m_building = true;
2826 if (!childPrim)
2827 DestroyBody();
2828 }
2829 else
2830 {
2831 m_building = false;
2832 CheckDelaySelect();
2833 if (!childPrim)
2834 MakeBody();
2835 }
2836 if (!childPrim && childrenPrim.Count > 0)
2837 {
2838 foreach (OdePrim prm in childrenPrim)
2839 prm.changeBuilding(m_building); // call directly
2840 }
2841 }
2842
2843 public void changeSetVehicle(VehicleData vdata)
2844 {
2845 if (m_vehicle == null)
2846 m_vehicle = new ODEDynamics(this);
2847 m_vehicle.DoSetVehicle(vdata);
2848 }
2849 private void changeVehicleType(int value)
2850 {
2851 if (value == (int)Vehicle.TYPE_NONE)
2852 {
2853 if (m_vehicle != null)
2854 m_vehicle = null;
2855 }
2856 else
2857 {
2858 if (m_vehicle == null)
2859 m_vehicle = new ODEDynamics(this);
2860
2861 m_vehicle.ProcessTypeChange((Vehicle)value);
2862 }
2863 }
2864
2865 private void changeVehicleFloatParam(strVehicleFloatParam fp)
2866 {
2867 if (m_vehicle == null)
2868 return;
2869
2870 m_vehicle.ProcessFloatVehicleParam((Vehicle)fp.param, fp.value);
2871 }
2872
2873 private void changeVehicleVectorParam(strVehicleVectorParam vp)
2874 {
2875 if (m_vehicle == null)
2876 return;
2877 m_vehicle.ProcessVectorVehicleParam((Vehicle)vp.param, vp.value);
2878 }
2879
2880 private void changeVehicleRotationParam(strVehicleQuatParam qp)
2881 {
2882 if (m_vehicle == null)
2883 return;
2884 m_vehicle.ProcessRotationVehicleParam((Vehicle)qp.param, qp.value);
2885 }
2886
2887 private void changeVehicleFlags(strVehicleBoolParam bp)
2888 {
2889 if (m_vehicle == null)
2890 return;
2891 m_vehicle.ProcessVehicleFlags(bp.param, bp.value);
2892 }
2893
2894 #endregion
2895
2896 public void Move()
2897 {
2898 if (!childPrim && m_isphysical && Body != IntPtr.Zero &&
2899 !m_disabled && !m_isSelected && d.BodyIsEnabled(Body) && !m_building && !m_outbounds)
2900 // !m_disabled && !m_isSelected && !m_building && !m_outbounds)
2901 {
2902// if (!d.BodyIsEnabled(Body)) d.BodyEnable(Body); // KF add 161009
2903
2904 float timestep = _parent_scene.ODE_STEPSIZE;
2905
2906 // check outside region
2907 d.Vector3 lpos;
2908 d.GeomCopyPosition(prim_geom, out lpos); // root position that is seem by rest of simulator
2909
2910 if (lpos.Z < -100 || lpos.Z > 100000f)
2911 {
2912 m_outbounds = true;
2913
2914 lpos.Z = Util.Clip(lpos.Z, -100f, 100000f);
2915 _acceleration.X = 0;
2916 _acceleration.Y = 0;
2917 _acceleration.Z = 0;
2918
2919 _velocity.X = 0;
2920 _velocity.Y = 0;
2921 _velocity.Z = 0;
2922 m_rotationalVelocity.X = 0;
2923 m_rotationalVelocity.Y = 0;
2924 m_rotationalVelocity.Z = 0;
2925
2926 d.BodySetLinearVel(Body, 0, 0, 0); // stop it
2927 d.BodySetAngularVel(Body, 0, 0, 0); // stop it
2928 d.BodySetPosition(Body, lpos.X, lpos.Y, lpos.Z); // put it somewhere
2929 m_lastposition = _position;
2930 m_lastorientation = _orientation;
2931
2932 base.RequestPhysicsterseUpdate();
2933
2934 m_throttleUpdates = false;
2935 throttleCounter = 0;
2936 _zeroFlag = true;
2937
2938 disableBodySoft(); // disable it and colisions
2939 base.RaiseOutOfBounds(_position);
2940 return;
2941 }
2942
2943 if (lpos.X < 0f)
2944 {
2945 _position.X = Util.Clip(lpos.X, -2f, -0.1f);
2946 m_outbounds = true;
2947 }
2948 else if(lpos.X > _parent_scene.WorldExtents.X)
2949 {
2950 _position.X = Util.Clip(lpos.X, _parent_scene.WorldExtents.X + 0.1f, _parent_scene.WorldExtents.X + 2f);
2951 m_outbounds = true;
2952 }
2953 if (lpos.Y < 0f)
2954 {
2955 _position.Y = Util.Clip(lpos.Y, -2f, -0.1f);
2956 m_outbounds = true;
2957 }
2958 else if(lpos.Y > _parent_scene.WorldExtents.Y)
2959 {
2960 _position.Y = Util.Clip(lpos.Y, _parent_scene.WorldExtents.Y + 0.1f, _parent_scene.WorldExtents.Y + 2f);
2961 m_outbounds = true;
2962 }
2963
2964 if(m_outbounds)
2965 {
2966 m_lastposition = _position;
2967 m_lastorientation = _orientation;
2968
2969 d.Vector3 dtmp = d.BodyGetAngularVel(Body);
2970 m_rotationalVelocity.X = dtmp.X;
2971 m_rotationalVelocity.Y = dtmp.Y;
2972 m_rotationalVelocity.Z = dtmp.Z;
2973
2974 dtmp = d.BodyGetLinearVel(Body);
2975 _velocity.X = dtmp.X;
2976 _velocity.Y = dtmp.Y;
2977 _velocity.Z = dtmp.Z;
2978
2979 d.BodySetLinearVel(Body, 0, 0, 0); // stop it
2980 d.BodySetAngularVel(Body, 0, 0, 0);
2981 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2982 disableBodySoft(); // stop collisions
2983 base.RequestPhysicsterseUpdate();
2984 return;
2985 }
2986
2987
2988 float fx = 0;
2989 float fy = 0;
2990 float fz = 0;
2991
2992 if (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE)
2993 {
2994 // 'VEHICLES' are dealt with in ODEDynamics.cs
2995 m_vehicle.Step();
2996 }
2997 else
2998 {
2999 float m_mass = _mass;
3000
3001 // fz = 0f;
3002 //m_log.Info(m_collisionFlags.ToString());
3003 if (m_usePID)
3004 {
3005
3006 // If the PID Controller isn't active then we set our force
3007 // calculating base velocity to the current position
3008
3009 if ((m_PIDTau < 1) && (m_PIDTau != 0))
3010 {
3011 //PID_G = PID_G / m_PIDTau;
3012 m_PIDTau = 1;
3013 }
3014
3015 if ((PID_G - m_PIDTau) <= 0)
3016 {
3017 PID_G = m_PIDTau + 1;
3018 }
3019
3020 d.Vector3 vel = d.BodyGetLinearVel(Body);
3021 d.Vector3 pos = d.BodyGetPosition(Body);
3022 _target_velocity =
3023 new Vector3(
3024 (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep),
3025 (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep),
3026 (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep)
3027 );
3028
3029 // if velocity is zero, use position control; otherwise, velocity control
3030
3031 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
3032 {
3033 // keep track of where we stopped. No more slippin' & slidin'
3034
3035 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3036 // react to the physics scene by moving it's position.
3037 // Avatar to Avatar collisions
3038 // Prim to avatar collisions
3039
3040 //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
3041 //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2);
3042 //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
3043 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3044 d.BodySetLinearVel(Body, 0, 0, 0);
3045 d.BodyAddForce(Body, 0, 0, fz);
3046 return;
3047 }
3048 else
3049 {
3050 _zeroFlag = false;
3051
3052 // We're flying and colliding with something
3053 fx = ((_target_velocity.X) - vel.X) * (PID_D);
3054 fy = ((_target_velocity.Y) - vel.Y) * (PID_D);
3055
3056 // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
3057
3058 fz = ((_target_velocity.Z - vel.Z) * (PID_D));
3059 }
3060 } // end if (m_usePID)
3061
3062 // Hover PID Controller needs to be mutually exlusive to MoveTo PID controller
3063 else if (m_useHoverPID)
3064 {
3065 //Console.WriteLine("Hover " + Name);
3066
3067 // If we're using the PID controller, then we have no gravity
3068
3069 // no lock; for now it's only called from within Simulate()
3070
3071 // If the PID Controller isn't active then we set our force
3072 // calculating base velocity to the current position
3073
3074 if ((m_PIDTau < 1))
3075 {
3076 PID_G = PID_G / m_PIDTau;
3077 }
3078
3079 if ((PID_G - m_PIDTau) <= 0)
3080 {
3081 PID_G = m_PIDTau + 1;
3082 }
3083
3084 // Where are we, and where are we headed?
3085 d.Vector3 pos = d.BodyGetPosition(Body);
3086 d.Vector3 vel = d.BodyGetLinearVel(Body);
3087
3088 // Non-Vehicles have a limited set of Hover options.
3089 // determine what our target height really is based on HoverType
3090 switch (m_PIDHoverType)
3091 {
3092 case PIDHoverType.Ground:
3093 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3094 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3095 break;
3096 case PIDHoverType.GroundAndWater:
3097 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3098 m_waterHeight = _parent_scene.GetWaterLevel();
3099 if (m_groundHeight > m_waterHeight)
3100 {
3101 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3102 }
3103 else
3104 {
3105 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
3106 }
3107 break;
3108
3109 } // end switch (m_PIDHoverType)
3110
3111
3112 _target_velocity =
3113 new Vector3(0.0f, 0.0f,
3114 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
3115 );
3116
3117 // if velocity is zero, use position control; otherwise, velocity control
3118
3119 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
3120 {
3121 // keep track of where we stopped. No more slippin' & slidin'
3122
3123 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3124 // react to the physics scene by moving it's position.
3125 // Avatar to Avatar collisions
3126 // Prim to avatar collisions
3127
3128 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
3129 d.BodySetLinearVel(Body, vel.X, vel.Y, 0);
3130 // ? d.BodyAddForce(Body, 0, 0, fz);
3131 return;
3132 }
3133 else
3134 {
3135 _zeroFlag = false;
3136
3137 // We're flying and colliding with something
3138 fz = ((_target_velocity.Z - vel.Z) * (PID_D));
3139 }
3140 }
3141 else
3142 {
3143 float b = (1.0f - m_buoyancy);
3144 fx = _parent_scene.gravityx * b;
3145 fy = _parent_scene.gravityy * b;
3146 fz = _parent_scene.gravityz * b;
3147 }
3148
3149 fx *= m_mass;
3150 fy *= m_mass;
3151 fz *= m_mass;
3152
3153 // constant force
3154 fx += m_force.X;
3155 fy += m_force.Y;
3156 fz += m_force.Z;
3157
3158 fx += m_forceacc.X;
3159 fy += m_forceacc.Y;
3160 fz += m_forceacc.Z;
3161
3162 m_forceacc = Vector3.Zero;
3163
3164 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
3165 if (fx != 0 || fy != 0 || fz != 0)
3166 {
3167 d.BodyAddForce(Body, fx, fy, fz);
3168 //Console.WriteLine("AddForce " + fx + "," + fy + "," + fz);
3169 }
3170
3171 Vector3 trq;
3172
3173 trq = _torque;
3174 trq += m_angularForceacc;
3175 m_angularForceacc = Vector3.Zero;
3176 if (trq.X != 0 || trq.Y != 0 || trq.Z != 0)
3177 {
3178 d.BodyAddTorque(Body, trq.X, trq.Y, trq.Z);
3179 }
3180
3181 }
3182 }
3183 else
3184 { // is not physical, or is not a body or is selected
3185 // _zeroPosition = d.BodyGetPosition(Body);
3186 return;
3187 //Console.WriteLine("Nothing " + Name);
3188
3189 }
3190 }
3191
3192
3193 public void UpdatePositionAndVelocity(float simulatedtime)
3194 {
3195 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
3196 if (_parent == null && !m_disabled && !m_building && !m_outbounds)
3197 {
3198 if (Body != IntPtr.Zero)
3199 {
3200 Vector3 pv = Vector3.Zero;
3201 bool lastZeroFlag = _zeroFlag;
3202
3203 d.Vector3 lpos;
3204 d.GeomCopyPosition(prim_geom, out lpos); // root position that is seem by rest of simulator
3205
3206
3207 d.Quaternion ori;
3208 d.GeomCopyQuaternion(prim_geom, out ori);
3209 d.Vector3 vel = d.BodyGetLinearVel(Body);
3210 d.Vector3 rotvel = d.BodyGetAngularVel(Body);
3211
3212 if ((Math.Abs(m_lastposition.X - lpos.X) < 0.01)
3213 && (Math.Abs(m_lastposition.Y - lpos.Y) < 0.01)
3214 && (Math.Abs(m_lastposition.Z - lpos.Z) < 0.01)
3215 && (Math.Abs(m_lastorientation.X - ori.X) < 0.0001)
3216 && (Math.Abs(m_lastorientation.Y - ori.Y) < 0.0001)
3217 && (Math.Abs(m_lastorientation.Z - ori.Z) < 0.0001)
3218 )
3219 {
3220 _zeroFlag = true;
3221 //Console.WriteLine("ZFT 2");
3222 m_throttleUpdates = false;
3223 }
3224 else
3225 {
3226 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
3227 _zeroFlag = false;
3228 m_lastUpdateSent = false;
3229 //m_throttleUpdates = false;
3230 }
3231
3232 if (_zeroFlag)
3233 {
3234 m_lastposition = _position;
3235 m_lastorientation = _orientation;
3236
3237 _velocity.X = 0.0f;
3238 _velocity.Y = 0.0f;
3239 _velocity.Z = 0.0f;
3240
3241 _acceleration.X = 0;
3242 _acceleration.Y = 0;
3243 _acceleration.Z = 0;
3244
3245 m_rotationalVelocity.X = 0;
3246 m_rotationalVelocity.Y = 0;
3247 m_rotationalVelocity.Z = 0;
3248 if (!m_lastUpdateSent)
3249 {
3250 m_throttleUpdates = false;
3251 throttleCounter = 0;
3252 m_rotationalVelocity = pv;
3253
3254 base.RequestPhysicsterseUpdate();
3255
3256 m_lastUpdateSent = true;
3257 }
3258 }
3259 else
3260 {
3261 if (lastZeroFlag != _zeroFlag)
3262 {
3263 base.RequestPhysicsterseUpdate();
3264 }
3265
3266 m_lastVelocity = _velocity;
3267
3268 _position.X = lpos.X;
3269 _position.Y = lpos.Y;
3270 _position.Z = lpos.Z;
3271
3272 _velocity.X = vel.X;
3273 _velocity.Y = vel.Y;
3274 _velocity.Z = vel.Z;
3275
3276 _orientation.X = ori.X;
3277 _orientation.Y = ori.Y;
3278 _orientation.Z = ori.Z;
3279 _orientation.W = ori.W;
3280
3281 _acceleration = ((_velocity - m_lastVelocity) / simulatedtime);
3282
3283 if (m_rotationalVelocity.ApproxEquals(pv, 0.0001f))
3284 {
3285 m_rotationalVelocity = pv;
3286 }
3287 else
3288 {
3289 m_rotationalVelocity.X = rotvel.X;
3290 m_rotationalVelocity.Y = rotvel.Y;
3291 m_rotationalVelocity.Z = rotvel.Z;
3292 }
3293
3294 m_lastUpdateSent = false;
3295 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
3296 {
3297 m_lastposition = _position;
3298 m_lastorientation = _orientation;
3299 base.RequestPhysicsterseUpdate();
3300 }
3301 else
3302 {
3303 throttleCounter++;
3304 }
3305 }
3306 }
3307 else if (!m_lastUpdateSent || !_zeroFlag)
3308 {
3309 // Not a body.. so Make sure the client isn't interpolating
3310 _velocity.X = 0;
3311 _velocity.Y = 0;
3312 _velocity.Z = 0;
3313
3314 _acceleration.X = 0;
3315 _acceleration.Y = 0;
3316 _acceleration.Z = 0;
3317
3318 m_rotationalVelocity.X = 0;
3319 m_rotationalVelocity.Y = 0;
3320 m_rotationalVelocity.Z = 0;
3321 _zeroFlag = true;
3322
3323 if (!m_lastUpdateSent)
3324 {
3325 m_throttleUpdates = false;
3326 throttleCounter = 0;
3327
3328 base.RequestPhysicsterseUpdate();
3329
3330 m_lastUpdateSent = true;
3331 }
3332 }
3333 }
3334 }
3335
3336 internal static bool QuaternionIsFinite(Quaternion q)
3337 {
3338 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
3339 return false;
3340 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
3341 return false;
3342 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
3343 return false;
3344 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
3345 return false;
3346 return true;
3347 }
3348
3349 internal static void DMassCopy(ref d.Mass src, ref d.Mass dst)
3350 {
3351 dst.c.W = src.c.W;
3352 dst.c.X = src.c.X;
3353 dst.c.Y = src.c.Y;
3354 dst.c.Z = src.c.Z;
3355 dst.mass = src.mass;
3356 dst.I.M00 = src.I.M00;
3357 dst.I.M01 = src.I.M01;
3358 dst.I.M02 = src.I.M02;
3359 dst.I.M10 = src.I.M10;
3360 dst.I.M11 = src.I.M11;
3361 dst.I.M12 = src.I.M12;
3362 dst.I.M20 = src.I.M20;
3363 dst.I.M21 = src.I.M21;
3364 dst.I.M22 = src.I.M22;
3365 }
3366
3367 private static void DMassDup(ref d.Mass src, out d.Mass dst)
3368 {
3369 dst = new d.Mass { };
3370
3371 dst.c.W = src.c.W;
3372 dst.c.X = src.c.X;
3373 dst.c.Y = src.c.Y;
3374 dst.c.Z = src.c.Z;
3375 dst.mass = src.mass;
3376 dst.I.M00 = src.I.M00;
3377 dst.I.M01 = src.I.M01;
3378 dst.I.M02 = src.I.M02;
3379 dst.I.M10 = src.I.M10;
3380 dst.I.M11 = src.I.M11;
3381 dst.I.M12 = src.I.M12;
3382 dst.I.M20 = src.I.M20;
3383 dst.I.M21 = src.I.M21;
3384 dst.I.M22 = src.I.M22;
3385 }
3386 private void donullchange()
3387 {
3388 }
3389
3390 public bool DoAChange(changes what, object arg)
3391 {
3392 if (prim_geom == IntPtr.Zero && what != changes.Add && what != changes.Remove)
3393 {
3394 return false;
3395 }
3396
3397 // nasty switch
3398 switch (what)
3399 {
3400 case changes.Add:
3401 changeadd();
3402 break;
3403 case changes.Remove:
3404 //If its being removed, we don't want to rebuild the physical rep at all, so ignore this stuff...
3405 //When we return true, it destroys all of the prims in the linkset anyway
3406 if (_parent != null)
3407 {
3408 OdePrim parent = (OdePrim)_parent;
3409 parent.ChildRemove(this, false);
3410 }
3411 else
3412 ChildRemove(this, false);
3413
3414 m_vehicle = null;
3415 RemoveGeom();
3416 m_targetSpace = IntPtr.Zero;
3417 if (m_eventsubscription > 0)
3418 UnSubscribeEvents();
3419 return true;
3420
3421 case changes.Link:
3422 OdePrim tmp = (OdePrim)arg;
3423 changeLink(tmp);
3424 break;
3425
3426 case changes.DeLink:
3427 changeLink(null);
3428 break;
3429
3430 case changes.Position:
3431 changePosition((Vector3)arg);
3432 break;
3433
3434 case changes.Orientation:
3435 changeOrientation((Quaternion)arg);
3436 break;
3437
3438 case changes.PosOffset:
3439 donullchange();
3440 break;
3441
3442 case changes.OriOffset:
3443 donullchange();
3444 break;
3445
3446 case changes.Velocity:
3447 changevelocity((Vector3)arg);
3448 break;
3449
3450 // case changes.Acceleration:
3451 // changeacceleration((Vector3)arg);
3452 // break;
3453 // case changes.AngVelocity:
3454 // changeangvelocity((Vector3)arg);
3455 // break;
3456
3457 case changes.Force:
3458 changeForce((Vector3)arg);
3459 break;
3460
3461 case changes.Torque:
3462 changeSetTorque((Vector3)arg);
3463 break;
3464
3465 case changes.AddForce:
3466 changeAddForce((Vector3)arg);
3467 break;
3468
3469 case changes.AddAngForce:
3470 changeAddAngularForce((Vector3)arg);
3471 break;
3472
3473 case changes.AngLock:
3474 changeAngularLock((Vector3)arg);
3475 break;
3476
3477 case changes.Size:
3478 changeSize((Vector3)arg);
3479 break;
3480
3481 case changes.Shape:
3482 changeShape((PrimitiveBaseShape)arg);
3483 break;
3484
3485 case changes.CollidesWater:
3486 changeFloatOnWater((bool)arg);
3487 break;
3488
3489 case changes.VolumeDtc:
3490 changeVolumedetetion((bool)arg);
3491 break;
3492
3493 case changes.Physical:
3494 changePhysicsStatus((bool)arg);
3495 break;
3496
3497 case changes.Selected:
3498 changeSelectedStatus((bool)arg);
3499 break;
3500
3501 case changes.disabled:
3502 changeDisable((bool)arg);
3503 break;
3504
3505 case changes.building:
3506 changeBuilding((bool)arg);
3507 break;
3508
3509 case changes.VehicleType:
3510 changeVehicleType((int)arg);
3511 break;
3512
3513 case changes.VehicleFlags:
3514 changeVehicleFlags((strVehicleBoolParam) arg);
3515 break;
3516
3517 case changes.VehicleFloatParam:
3518 changeVehicleFloatParam((strVehicleFloatParam) arg);
3519 break;
3520
3521 case changes.VehicleVectorParam:
3522 changeVehicleVectorParam((strVehicleVectorParam) arg);
3523 break;
3524
3525 case changes.VehicleRotationParam:
3526 changeVehicleRotationParam((strVehicleQuatParam) arg);
3527 break;
3528
3529 case changes.SetVehicle:
3530 changeSetVehicle((VehicleData) arg);
3531 break;
3532 case changes.Null:
3533 donullchange();
3534 break;
3535
3536 default:
3537 donullchange();
3538 break;
3539 }
3540 return false;
3541 }
3542
3543 public void AddChange(changes what, object arg)
3544 {
3545 _parent_scene.AddChange((PhysicsActor) this, what, arg);
3546 }
3547
3548
3549 private struct strVehicleBoolParam
3550 {
3551 public int param;
3552 public bool value;
3553 }
3554
3555 private struct strVehicleFloatParam
3556 {
3557 public int param;
3558 public float value;
3559 }
3560
3561 private struct strVehicleQuatParam
3562 {
3563 public int param;
3564 public Quaternion value;
3565 }
3566
3567 private struct strVehicleVectorParam
3568 {
3569 public int param;
3570 public Vector3 value;
3571 }
3572 }
3573} \ No newline at end of file