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