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