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