aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/ChOdePlugin
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/ChOdePlugin')
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs1421
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs3910
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs375
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs48
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs3859
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs122
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs98
8 files changed, 9891 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs
new file mode 100644
index 0000000..d65929a
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs
@@ -0,0 +1,58 @@
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
28using System.Reflection;
29using System.Runtime.InteropServices;
30
31// Information about this assembly is defined by the following
32// attributes.
33//
34// change them to the information which is associated with the assembly
35// you compile.
36
37[assembly : AssemblyTitle("OdePlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("OdePlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.6.5.*")]
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs
new file mode 100644
index 0000000..61c16b8
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs
@@ -0,0 +1,1421 @@
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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using Ode.NET;
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35using log4net;
36
37namespace OpenSim.Region.Physics.OdePlugin
38{
39 /// <summary>
40 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
41 /// </summary>
42
43 public enum dParam : int
44 {
45 LowStop = 0,
46 HiStop = 1,
47 Vel = 2,
48 FMax = 3,
49 FudgeFactor = 4,
50 Bounce = 5,
51 CFM = 6,
52 StopERP = 7,
53 StopCFM = 8,
54 LoStop2 = 256,
55 HiStop2 = 257,
56 Vel2 = 258,
57 FMax2 = 259,
58 StopERP2 = 7 + 256,
59 StopCFM2 = 8 + 256,
60 LoStop3 = 512,
61 HiStop3 = 513,
62 Vel3 = 514,
63 FMax3 = 515,
64 StopERP3 = 7 + 512,
65 StopCFM3 = 8 + 512
66 }
67 public class OdeCharacter : PhysicsActor
68 {
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
71 private Vector3 _position;
72 private d.Vector3 _zeroPosition;
73 // private d.Matrix3 m_StandUpRotation;
74 private bool _zeroFlag = false;
75 private bool m_lastUpdateSent = false;
76 private Vector3 _velocity;
77 private Vector3 _target_velocity;
78 private Vector3 _acceleration;
79 private Vector3 m_rotationalVelocity;
80 private float m_mass = 80f;
81 public float m_density = 60f;
82 private bool m_pidControllerActive = true;
83 public float PID_D = 800.0f;
84 public float PID_P = 900.0f;
85 //private static float POSTURE_SERVO = 10000.0f;
86 public float CAPSULE_RADIUS = 0.37f;
87 public float CAPSULE_LENGTH = 2.140599f;
88 public float m_tensor = 3800000f;
89 public float heightFudgeFactor = 0.52f;
90 public float walkDivisor = 1.3f;
91 public float runDivisor = 0.8f;
92 private bool flying = false;
93 private bool m_iscolliding = false;
94 private bool m_iscollidingGround = false;
95 private bool m_wascolliding = false;
96 private bool m_wascollidingGround = false;
97 private bool m_iscollidingObj = false;
98 private bool m_alwaysRun = false;
99 private bool m_hackSentFall = false;
100 private bool m_hackSentFly = false;
101 private int m_requestedUpdateFrequency = 0;
102 private Vector3 m_taintPosition = Vector3.Zero;
103 public uint m_localID = 0;
104 public bool m_returnCollisions = false;
105 // taints and their non-tainted counterparts
106 public bool m_isPhysical = false; // the current physical status
107 public bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing)
108 public float MinimumGroundFlightOffset = 3f;
109
110 private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes.
111 private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f; // used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider
112
113
114 private float m_buoyancy = 0f;
115
116 // private CollisionLocker ode;
117
118 private string m_name = String.Empty;
119
120 private bool[] m_colliderarr = new bool[11];
121 private bool[] m_colliderGroundarr = new bool[11];
122
123 // Default we're a Character
124 private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
125
126 // Default, Collide with Other Geometries, spaces, bodies and characters.
127 private CollisionCategories m_collisionFlags = (CollisionCategories.Geom
128 | CollisionCategories.Space
129 | CollisionCategories.Body
130 | CollisionCategories.Character
131 | CollisionCategories.Land);
132 public IntPtr Body = IntPtr.Zero;
133 private OdeScene _parent_scene;
134 public IntPtr Shell = IntPtr.Zero;
135 public IntPtr Amotor = IntPtr.Zero;
136 public d.Mass ShellMass;
137 public bool collidelock = false;
138
139 public int m_eventsubscription = 0;
140 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
141
142 // unique UUID of this character object
143 public UUID m_uuid;
144 public bool bad = false;
145
146 public OdeCharacter(String avName, OdeScene parent_scene, Vector3 pos, CollisionLocker dode, Vector3 size, float pid_d, float pid_p, float capsule_radius, float tensor, float density, float height_fudge_factor, float walk_divisor, float rundivisor)
147 {
148 m_uuid = UUID.Random();
149
150 if (pos.IsFinite())
151 {
152 if (pos.Z > 9999999f)
153 {
154 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
155 }
156 if (pos.Z < -90000f)
157 {
158 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
159 }
160 _position = pos;
161 m_taintPosition.X = pos.X;
162 m_taintPosition.Y = pos.Y;
163 m_taintPosition.Z = pos.Z;
164 }
165 else
166 {
167 _position = new Vector3(((float)_parent_scene.WorldExtents.X * 0.5f), ((float)_parent_scene.WorldExtents.Y * 0.5f), parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f);
168 m_taintPosition.X = _position.X;
169 m_taintPosition.Y = _position.Y;
170 m_taintPosition.Z = _position.Z;
171 m_log.Warn("[PHYSICS]: Got NaN Position on Character Create");
172 }
173
174 _parent_scene = parent_scene;
175
176 PID_D = pid_d;
177 PID_P = pid_p;
178 CAPSULE_RADIUS = capsule_radius;
179 m_tensor = tensor;
180 m_density = density;
181 heightFudgeFactor = height_fudge_factor;
182 walkDivisor = walk_divisor;
183 runDivisor = rundivisor;
184
185 // m_StandUpRotation =
186 // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f,
187 // 0.5f);
188
189 for (int i = 0; i < 11; i++)
190 {
191 m_colliderarr[i] = false;
192 }
193 CAPSULE_LENGTH = (size.Z * 1.15f) - CAPSULE_RADIUS * 2.0f;
194 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
195 m_tainted_CAPSULE_LENGTH = CAPSULE_LENGTH;
196
197 m_isPhysical = false; // current status: no ODE information exists
198 m_tainted_isPhysical = true; // new tainted status: need to create ODE information
199
200 _parent_scene.AddPhysicsActorTaint(this);
201
202 m_name = avName;
203 }
204
205 public override int PhysicsActorType
206 {
207 get { return (int) ActorTypes.Agent; }
208 set { return; }
209 }
210
211 /// <summary>
212 /// If this is set, the avatar will move faster
213 /// </summary>
214 public override bool SetAlwaysRun
215 {
216 get { return m_alwaysRun; }
217 set { m_alwaysRun = value; }
218 }
219
220 public override uint LocalID
221 {
222 set { m_localID = value; }
223 }
224
225 public override bool Grabbed
226 {
227 set { return; }
228 }
229
230 public override bool Selected
231 {
232 set { return; }
233 }
234
235 public override float Buoyancy
236 {
237 get { return m_buoyancy; }
238 set { m_buoyancy = value; }
239 }
240
241 public override bool FloatOnWater
242 {
243 set { return; }
244 }
245
246 public override bool IsPhysical
247 {
248 get { return false; }
249 set { return; }
250 }
251
252 public override bool ThrottleUpdates
253 {
254 get { return false; }
255 set { return; }
256 }
257
258 public override bool Flying
259 {
260 get { return flying; }
261 set { flying = value; }
262 }
263
264 /// <summary>
265 /// Returns if the avatar is colliding in general.
266 /// This includes the ground and objects and avatar.
267 /// </summary>
268 public override bool IsColliding
269 {
270 get { return m_iscolliding; }
271 set
272 {
273 int i;
274 int truecount = 0;
275 int falsecount = 0;
276
277 if (m_colliderarr.Length >= 10)
278 {
279 for (i = 0; i < 10; i++)
280 {
281 m_colliderarr[i] = m_colliderarr[i + 1];
282 }
283 }
284 m_colliderarr[10] = value;
285
286 for (i = 0; i < 11; i++)
287 {
288 if (m_colliderarr[i])
289 {
290 truecount++;
291 }
292 else
293 {
294 falsecount++;
295 }
296 }
297
298 // Equal truecounts and false counts means we're colliding with something.
299
300 if (falsecount > 1.2*truecount)
301 {
302 m_iscolliding = false;
303 }
304 else
305 {
306 m_iscolliding = true;
307 }
308 if (m_wascolliding != m_iscolliding)
309 {
310 //base.SendCollisionUpdate(new CollisionEventUpdate());
311 }
312 m_wascolliding = m_iscolliding;
313 }
314 }
315
316 /// <summary>
317 /// Returns if an avatar is colliding with the ground
318 /// </summary>
319 public override bool CollidingGround
320 {
321 get { return m_iscollidingGround; }
322 set
323 {
324 // Collisions against the ground are not really reliable
325 // So, to get a consistant value we have to average the current result over time
326 // Currently we use 1 second = 10 calls to this.
327 int i;
328 int truecount = 0;
329 int falsecount = 0;
330
331 if (m_colliderGroundarr.Length >= 10)
332 {
333 for (i = 0; i < 10; i++)
334 {
335 m_colliderGroundarr[i] = m_colliderGroundarr[i + 1];
336 }
337 }
338 m_colliderGroundarr[10] = value;
339
340 for (i = 0; i < 11; i++)
341 {
342 if (m_colliderGroundarr[i])
343 {
344 truecount++;
345 }
346 else
347 {
348 falsecount++;
349 }
350 }
351
352 // Equal truecounts and false counts means we're colliding with something.
353
354 if (falsecount > 1.2*truecount)
355 {
356 m_iscollidingGround = false;
357 }
358 else
359 {
360 m_iscollidingGround = true;
361 }
362 if (m_wascollidingGround != m_iscollidingGround)
363 {
364 //base.SendCollisionUpdate(new CollisionEventUpdate());
365 }
366 m_wascollidingGround = m_iscollidingGround;
367 }
368 }
369
370 /// <summary>
371 /// Returns if the avatar is colliding with an object
372 /// </summary>
373 public override bool CollidingObj
374 {
375 get { return m_iscollidingObj; }
376 set
377 {
378 m_iscollidingObj = value;
379 if (value)
380 m_pidControllerActive = false;
381 else
382 m_pidControllerActive = true;
383 }
384 }
385
386 /// <summary>
387 /// turn the PID controller on or off.
388 /// The PID Controller will turn on all by itself in many situations
389 /// </summary>
390 /// <param name="status"></param>
391 public void SetPidStatus(bool status)
392 {
393 m_pidControllerActive = status;
394 }
395
396 public override bool Stopped
397 {
398 get { return _zeroFlag; }
399 }
400
401 /// <summary>
402 /// This 'puts' an avatar somewhere in the physics space.
403 /// Not really a good choice unless you 'know' it's a good
404 /// spot otherwise you're likely to orbit the avatar.
405 /// </summary>
406 public override Vector3 Position
407 {
408 get { return _position; }
409 set
410 {
411 if (Body == IntPtr.Zero || Shell == IntPtr.Zero)
412 {
413 if (value.IsFinite())
414 {
415 if (value.Z > 9999999f)
416 {
417 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
418 }
419 if (value.Z < -90000f)
420 {
421 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
422 }
423
424 _position.X = value.X;
425 _position.Y = value.Y;
426 _position.Z = value.Z;
427
428 m_taintPosition.X = value.X;
429 m_taintPosition.Y = value.Y;
430 m_taintPosition.Z = value.Z;
431 _parent_scene.AddPhysicsActorTaint(this);
432 }
433 else
434 {
435 m_log.Warn("[PHYSICS]: Got a NaN Position from Scene on a Character");
436 }
437 }
438 }
439 }
440
441 public override Vector3 RotationalVelocity
442 {
443 get { return m_rotationalVelocity; }
444 set { m_rotationalVelocity = value; }
445 }
446
447 /// <summary>
448 /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight
449 /// and use it to offset landings properly
450 /// </summary>
451 public override Vector3 Size
452 {
453 get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); }
454 set
455 {
456 if (value.IsFinite())
457 {
458 m_pidControllerActive = true;
459
460 Vector3 SetSize = value;
461 m_tainted_CAPSULE_LENGTH = (SetSize.Z*1.15f) - CAPSULE_RADIUS*2.0f;
462 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
463
464 Velocity = Vector3.Zero;
465
466 _parent_scene.AddPhysicsActorTaint(this);
467 }
468 else
469 {
470 m_log.Warn("[PHYSICS]: Got a NaN Size from Scene on a Character");
471 }
472 }
473 }
474
475 private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector)
476 {
477 movementVector.Z = 0f;
478 float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y));
479 if (magnitude < 0.1f) return;
480
481 // normalize the velocity vector
482 float invMagnitude = 1.0f / magnitude;
483 movementVector.X *= invMagnitude;
484 movementVector.Y *= invMagnitude;
485
486 // if we change the capsule heading too often, the capsule can fall down
487 // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw),
488 // meaning only 4 possible capsule tilt orientations
489 if (movementVector.X > 0)
490 {
491 // east
492 if (movementVector.Y > 0)
493 {
494 // northeast
495 movementVector.X = (float)Math.Sqrt(2.0);
496 movementVector.Y = (float)Math.Sqrt(2.0);
497 }
498 else
499 {
500 // southeast
501 movementVector.X = (float)Math.Sqrt(2.0);
502 movementVector.Y = -(float)Math.Sqrt(2.0);
503 }
504 }
505 else
506 {
507 // west
508 if (movementVector.Y > 0)
509 {
510 // northwest
511 movementVector.X = -(float)Math.Sqrt(2.0);
512 movementVector.Y = (float)Math.Sqrt(2.0);
513 }
514 else
515 {
516 // southwest
517 movementVector.X = -(float)Math.Sqrt(2.0);
518 movementVector.Y = -(float)Math.Sqrt(2.0);
519 }
520 }
521
522
523 // movementVector.Z is zero
524
525 // calculate tilt components based on desired amount of tilt and current (snapped) heading.
526 // the "-" sign is to force the tilt to be OPPOSITE the direction of movement.
527 float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane;
528 float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane;
529
530 //m_log.Debug("[PHYSICS] changing avatar tilt");
531 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent);
532 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced
533 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent);
534 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop
535 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
536 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
537 }
538
539 /// <summary>
540 /// This creates the Avatar's physical Surrogate at the position supplied
541 /// </summary>
542 /// <param name="npositionX"></param>
543 /// <param name="npositionY"></param>
544 /// <param name="npositionZ"></param>
545
546 // WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access
547 // to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only
548 // place that is safe to call this routine AvatarGeomAndBodyCreation.
549 private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ, float tensor)
550 {
551 //CAPSULE_LENGTH = -5;
552 //CAPSULE_RADIUS = -5;
553 int dAMotorEuler = 1;
554 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
555 if (CAPSULE_LENGTH <= 0)
556 {
557 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
558 CAPSULE_LENGTH = 0.01f;
559
560 }
561
562 if (CAPSULE_RADIUS <= 0)
563 {
564 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
565 CAPSULE_RADIUS = 0.01f;
566
567 }
568
569 if(Shell != IntPtr.Zero)
570 {
571 try
572 {
573 d.GeomDestroy(Shell);
574 }
575 catch (System.AccessViolationException)
576 {
577 m_log.Error("[PHYSICS]: PrimGeom dead");
578 }
579 // Remove any old entries
580//string tShell;
581//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
582//Console.WriteLine("**** Remove {0}", tShell);
583 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
584 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
585 }
586
587 Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
588 _parent_scene.geom_name_map[Shell] = m_name;
589 _parent_scene.actor_name_map[Shell] = (PhysicsActor)this;
590//Console.WriteLine("**** Create {2} Dicts: actor={0} name={1}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, m_name);
591
592 d.GeomSetCategoryBits(Shell, (int)m_collisionCategories);
593 d.GeomSetCollideBits(Shell, (int)m_collisionFlags);
594
595 d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH);
596 Body = d.BodyCreate(_parent_scene.world);
597 d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
598
599 _position.X = npositionX;
600 _position.Y = npositionY;
601 _position.Z = npositionZ;
602
603
604 m_taintPosition.X = npositionX;
605 m_taintPosition.Y = npositionY;
606 m_taintPosition.Z = npositionZ;
607
608 d.BodySetMass(Body, ref ShellMass);
609 d.Matrix3 m_caprot;
610 // 90 Stand up on the cap of the capped cyllinder
611 if (_parent_scene.IsAvCapsuleTilted)
612 {
613 d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2));
614 }
615 else
616 {
617 d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2));
618 }
619
620
621 d.GeomSetRotation(Shell, ref m_caprot);
622 d.BodySetRotation(Body, ref m_caprot);
623
624 d.GeomSetBody(Shell, Body);
625
626
627 // The purpose of the AMotor here is to keep the avatar's physical
628 // surrogate from rotating while moving
629 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
630 d.JointAttach(Amotor, Body, IntPtr.Zero);
631 d.JointSetAMotorMode(Amotor, dAMotorEuler);
632 d.JointSetAMotorNumAxes(Amotor, 3);
633 d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
634 d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
635 d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
636 d.JointSetAMotorAngle(Amotor, 0, 0);
637 d.JointSetAMotorAngle(Amotor, 1, 0);
638 d.JointSetAMotorAngle(Amotor, 2, 0);
639
640 // These lowstops and high stops are effectively (no wiggle room)
641 if (_parent_scene.IsAvCapsuleTilted)
642 {
643 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f);
644 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f);
645 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f);
646 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f);
647 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f);
648 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f);
649 }
650 else
651 {
652 #region Documentation of capsule motor LowStop and HighStop parameters
653 // Intentionally introduce some tilt into the capsule by setting
654 // the motor stops to small epsilon values. This small tilt prevents
655 // the capsule from falling into the terrain; a straight-up capsule
656 // (with -0..0 motor stops) falls into the terrain for reasons yet
657 // to be comprehended in their entirety.
658 #endregion
659 AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero);
660 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f);
661 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
662 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f);
663 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced
664 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
665 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop
666 }
667
668 // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the
669 // capped cyllinder will fall over
670 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
671 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor);
672
673 //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
674 //d.QfromR(
675 //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068,
676 //
677 //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
678 //standupStraight();
679 }
680
681 //
682 /// <summary>
683 /// Uses the capped cyllinder volume formula to calculate the avatar's mass.
684 /// This may be used in calculations in the scene/scenepresence
685 /// </summary>
686 public override float Mass
687 {
688 get
689 {
690 float AVvolume = (float) (Math.PI*Math.Pow(CAPSULE_RADIUS, 2)*CAPSULE_LENGTH);
691 return m_density*AVvolume;
692 }
693 }
694 public override void link(PhysicsActor obj)
695 {
696
697 }
698
699 public override void delink()
700 {
701
702 }
703
704 public override void LockAngularMotion(Vector3 axis)
705 {
706
707 }
708
709// This code is very useful. Written by DanX0r. We're just not using it right now.
710// Commented out to prevent a warning.
711//
712// private void standupStraight()
713// {
714// // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air.
715// // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you
716// // change appearance and when you enter the simulator
717// // After this routine is done, the amotor stabilizes much quicker
718// d.Vector3 feet;
719// d.Vector3 head;
720// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
721// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
722// float posture = head.Z - feet.Z;
723
724// // restoring force proportional to lack of posture:
725// float servo = (2.5f - posture) * POSTURE_SERVO;
726// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
727// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
728// //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
729// //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
730// }
731
732 public override Vector3 Force
733 {
734 get { return _target_velocity; }
735 set { return; }
736 }
737
738 public override int VehicleType
739 {
740 get { return 0; }
741 set { return; }
742 }
743
744 public override void VehicleFloatParam(int param, float value)
745 {
746
747 }
748
749 public override void VehicleVectorParam(int param, Vector3 value)
750 {
751
752 }
753
754 public override void VehicleRotationParam(int param, Quaternion rotation)
755 {
756
757 }
758
759 public override void VehicleFlags(int flags, bool remove)
760 {
761 }
762
763 public override void SetVolumeDetect(int param)
764 {
765
766 }
767
768 public override Vector3 CenterOfMass
769 {
770 get { return Vector3.Zero; }
771 }
772
773 public override Vector3 GeometricCenter
774 {
775 get { return Vector3.Zero; }
776 }
777
778 public override PrimitiveBaseShape Shape
779 {
780 set { return; }
781 }
782
783 public override Vector3 Velocity
784 {
785 get {
786 // There's a problem with Vector3.Zero! Don't Use it Here!
787 if (_zeroFlag)
788 return Vector3.Zero;
789 m_lastUpdateSent = false;
790 return _velocity;
791 }
792 set
793 {
794 if (value.IsFinite())
795 {
796 m_pidControllerActive = true;
797 _target_velocity = value;
798 }
799 else
800 {
801 m_log.Warn("[PHYSICS]: Got a NaN velocity from Scene in a Character");
802 }
803 }
804 }
805
806 public override Vector3 Torque
807 {
808 get { return Vector3.Zero; }
809 set { return; }
810 }
811
812 public override float CollisionScore
813 {
814 get { return 0f; }
815 set { }
816 }
817
818 public override bool Kinematic
819 {
820 get { return false; }
821 set { }
822 }
823
824 public override Quaternion Orientation
825 {
826 get { return Quaternion.Identity; }
827 set {
828 //Matrix3 or = Orientation.ToRotationMatrix();
829 //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22);
830 //d.BodySetRotation(Body, ref ord);
831 }
832 }
833
834 public override Vector3 Acceleration
835 {
836 get { return _acceleration; }
837 }
838
839 public void SetAcceleration(Vector3 accel)
840 {
841 m_pidControllerActive = true;
842 _acceleration = accel;
843 }
844
845 /// <summary>
846 /// Adds the force supplied to the Target Velocity
847 /// The PID controller takes this target velocity and tries to make it a reality
848 /// </summary>
849 /// <param name="force"></param>
850 public override void AddForce(Vector3 force, bool pushforce)
851 {
852 if (force.IsFinite())
853 {
854 if (pushforce)
855 {
856 m_pidControllerActive = false;
857 force *= 100f;
858 doForce(force);
859 // If uncommented, things get pushed off world
860 //
861 // m_log.Debug("Push!");
862 // _target_velocity.X += force.X;
863 // _target_velocity.Y += force.Y;
864 // _target_velocity.Z += force.Z;
865 }
866 else
867 {
868 m_pidControllerActive = true;
869 _target_velocity.X += force.X;
870 _target_velocity.Y += force.Y;
871 _target_velocity.Z += force.Z;
872 }
873 }
874 else
875 {
876 m_log.Warn("[PHYSICS]: Got a NaN force applied to a Character");
877 }
878 //m_lastUpdateSent = false;
879 }
880
881 public override void AddAngularForce(Vector3 force, bool pushforce)
882 {
883
884 }
885
886 /// <summary>
887 /// After all of the forces add up with 'add force' we apply them with doForce
888 /// </summary>
889 /// <param name="force"></param>
890 public void doForce(Vector3 force)
891 {
892 if (!collidelock)
893 {
894 d.BodyAddForce(Body, force.X, force.Y, force.Z);
895 //d.BodySetRotation(Body, ref m_StandUpRotation);
896 //standupStraight();
897
898 }
899 }
900
901 public override void SetMomentum(Vector3 momentum)
902 {
903 }
904
905
906 /// <summary>
907 /// Called from Simulate
908 /// This is the avatar's movement control + PID Controller
909 /// </summary>
910 /// <param name="timeStep"></param>
911 public void Move(float timeStep, List<OdeCharacter> defects)
912 {
913 // no lock; for now it's only called from within Simulate()
914
915 // If the PID Controller isn't active then we set our force
916 // calculating base velocity to the current position
917
918 if (Body == IntPtr.Zero)
919 return;
920
921 if (m_pidControllerActive == false)
922 {
923 _zeroPosition = d.BodyGetPosition(Body);
924 }
925 //PidStatus = true;
926
927 d.Vector3 localpos = d.BodyGetPosition(Body);
928 Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z);
929
930 if (!localPos.IsFinite())
931 {
932
933 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
934 defects.Add(this);
935 // _parent_scene.RemoveCharacter(this);
936
937 // destroy avatar capsule and related ODE data
938 if (Amotor != IntPtr.Zero)
939 {
940 // Kill the Amotor
941 d.JointDestroy(Amotor);
942 Amotor = IntPtr.Zero;
943 }
944
945 //kill the Geometry
946 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
947
948 if (Body != IntPtr.Zero)
949 {
950 //kill the body
951 d.BodyDestroy(Body);
952
953 Body = IntPtr.Zero;
954 }
955
956 if(Shell != IntPtr.Zero)
957 {
958 try
959 {
960 d.GeomDestroy(Shell);
961 }
962 catch (System.AccessViolationException)
963 {
964 m_log.Error("[PHYSICS]: PrimGeom dead");
965 }
966 // Remove any old entries
967//string tShell;
968//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
969//Console.WriteLine("**** Remove {0}", tShell);
970
971 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
972 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
973 Shell = IntPtr.Zero;
974 }
975
976 return;
977 }
978
979 Vector3 vec = Vector3.Zero;
980 d.Vector3 vel = d.BodyGetLinearVel(Body);
981
982 float movementdivisor = 1f;
983
984 if (!m_alwaysRun)
985 {
986 movementdivisor = walkDivisor;
987 }
988 else
989 {
990 movementdivisor = runDivisor;
991 }
992
993 // if velocity is zero, use position control; otherwise, velocity control
994 if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding)
995 {
996 // keep track of where we stopped. No more slippin' & slidin'
997 if (!_zeroFlag)
998 {
999 _zeroFlag = true;
1000 _zeroPosition = d.BodyGetPosition(Body);
1001 }
1002 if (m_pidControllerActive)
1003 {
1004 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1005 // react to the physics scene by moving it's position.
1006 // Avatar to Avatar collisions
1007 // Prim to avatar collisions
1008
1009 d.Vector3 pos = d.BodyGetPosition(Body);
1010 float errX = _zeroPosition.X - pos.X;
1011 float errY = _zeroPosition.Y - pos.Y;
1012 if( (Math.Abs(errX) > 0.1f) || (Math.Abs(errY) > 0.1f) )
1013 {
1014 vec.X = (_target_velocity.X - vel.X) * (PID_D) + (errX) * (PID_P * 2);
1015 vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (errY) * (PID_P * 2);
1016 }
1017 else
1018 { // close, jump to lateral destination
1019 d.BodySetPosition(Body, _zeroPosition.X, _zeroPosition.Y, pos.Z);
1020 }
1021 if (flying)
1022 {
1023 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
1024 }
1025 }
1026 //PidStatus = true;
1027 }
1028 else
1029 {
1030 m_pidControllerActive = true;
1031 _zeroFlag = false;
1032 if (m_iscolliding && !flying)
1033 {
1034 // We're standing on something
1035 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D);
1036 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D);
1037 }
1038 else if (m_iscolliding && flying)
1039 {
1040 // We're flying and colliding with something
1041 vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*(PID_D / 16);
1042 vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*(PID_D / 16);
1043 }
1044 else if (!m_iscolliding && flying)
1045 {
1046 // we're in mid air suspended
1047 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D/6);
1048 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D/6);
1049 }
1050
1051 if (m_iscolliding && !flying && _target_velocity.Z > 0.0f)
1052 {
1053 // We're colliding with something and we're not flying but we're moving
1054 // This means we're walking or running.
1055 d.Vector3 pos = d.BodyGetPosition(Body);
1056 vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P;
1057 if (_target_velocity.X > 0)
1058 {
1059 vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D;
1060 }
1061 if (_target_velocity.Y > 0)
1062 {
1063 vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D;
1064 }
1065 }
1066 else if (!m_iscolliding && !flying)
1067 {
1068 // we're not colliding and we're not flying so that means we're falling!
1069 // m_iscolliding includes collisions with the ground.
1070
1071 // d.Vector3 pos = d.BodyGetPosition(Body);
1072 if (Math.Abs(_target_velocity.X) > 0)
1073 {
1074 vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D;
1075 }
1076 if (Math.Abs(_target_velocity.Y) > 0)
1077 {
1078 vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D;
1079 }
1080 }
1081
1082 if (flying)
1083 {
1084 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D);
1085 }
1086 }
1087 if (flying)
1088 {
1089 vec.Z += ((-1 * _parent_scene.gravityz)*m_mass);
1090
1091 //Added for auto fly height. Kitto Flora
1092 //d.Vector3 pos = d.BodyGetPosition(Body);
1093 float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset;
1094
1095 if (_position.Z < target_altitude)
1096 {
1097 vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f;
1098 }
1099 // end add Kitto Flora
1100 }
1101 if (vec.IsFinite())
1102 {
1103 if (!vec.ApproxEquals(Vector3.Zero, 0.01f))
1104 {
1105 doForce(vec);
1106 if (!_zeroFlag)
1107 {
1108 AlignAvatarTiltWithCurrentDirectionOfMovement(vec);
1109 }
1110 }
1111 }
1112 else
1113 {
1114 m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()");
1115 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
1116 defects.Add(this);
1117 // _parent_scene.RemoveCharacter(this);
1118 // destroy avatar capsule and related ODE data
1119 if (Amotor != IntPtr.Zero)
1120 {
1121 // Kill the Amotor
1122 d.JointDestroy(Amotor);
1123 Amotor = IntPtr.Zero;
1124 }
1125 //kill the Geometry
1126 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1127
1128 if (Body != IntPtr.Zero)
1129 {
1130 //kill the body
1131 d.BodyDestroy(Body);
1132
1133 Body = IntPtr.Zero;
1134 }
1135
1136 if(Shell != IntPtr.Zero)
1137 {
1138 try
1139 {
1140 d.GeomDestroy(Shell);
1141 }
1142 catch (System.AccessViolationException)
1143 {
1144 m_log.Error("[PHYSICS]: PrimGeom dead");
1145 }
1146 // Remove any old entries
1147//string tShell;
1148//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
1149//Console.WriteLine("**** Remove {0}", tShell);
1150
1151 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
1152 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
1153 Shell = IntPtr.Zero;
1154 }
1155 }
1156 }
1157
1158 /// <summary>
1159 /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
1160 /// </summary>
1161 public void UpdatePositionAndVelocity()
1162 {
1163 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
1164 d.Vector3 vec;
1165 try
1166 {
1167 vec = d.BodyGetPosition(Body);
1168 }
1169 catch (NullReferenceException)
1170 {
1171 bad = true;
1172 _parent_scene.BadCharacter(this);
1173 vec = new d.Vector3(_position.X, _position.Y, _position.Z);
1174 base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem!
1175 m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid);
1176 }
1177
1178
1179 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
1180 if (vec.X < 0.0f) vec.X = 0.0f;
1181 if (vec.Y < 0.0f) vec.Y = 0.0f;
1182 if (vec.X > (int)_parent_scene.WorldExtents.X - 0.05f) vec.X = (int)_parent_scene.WorldExtents.X - 0.05f;
1183 if (vec.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) vec.Y = (int)_parent_scene.WorldExtents.Y - 0.05f;
1184
1185 _position.X = vec.X;
1186 _position.Y = vec.Y;
1187 _position.Z = vec.Z;
1188
1189 // Did we move last? = zeroflag
1190 // This helps keep us from sliding all over
1191
1192 if (_zeroFlag)
1193 {
1194 _velocity.X = 0.0f;
1195 _velocity.Y = 0.0f;
1196 _velocity.Z = 0.0f;
1197
1198 // Did we send out the 'stopped' message?
1199 if (!m_lastUpdateSent)
1200 {
1201 m_lastUpdateSent = true;
1202 //base.RequestPhysicsterseUpdate();
1203
1204 }
1205 }
1206 else
1207 {
1208 m_lastUpdateSent = false;
1209 try
1210 {
1211 vec = d.BodyGetLinearVel(Body);
1212 }
1213 catch (NullReferenceException)
1214 {
1215 vec.X = _velocity.X;
1216 vec.Y = _velocity.Y;
1217 vec.Z = _velocity.Z;
1218 }
1219 _velocity.X = (vec.X);
1220 _velocity.Y = (vec.Y);
1221
1222 _velocity.Z = (vec.Z);
1223
1224 if (_velocity.Z < -6 && !m_hackSentFall)
1225 {
1226 m_hackSentFall = true;
1227 m_pidControllerActive = false;
1228 }
1229 else if (flying && !m_hackSentFly)
1230 {
1231 //m_hackSentFly = true;
1232 //base.SendCollisionUpdate(new CollisionEventUpdate());
1233 }
1234 else
1235 {
1236 m_hackSentFly = false;
1237 m_hackSentFall = false;
1238 }
1239 }
1240 }
1241
1242 /// <summary>
1243 /// Cleanup the things we use in the scene.
1244 /// </summary>
1245 public void Destroy()
1246 {
1247 m_tainted_isPhysical = false;
1248 _parent_scene.AddPhysicsActorTaint(this);
1249 }
1250
1251 public override void CrossingFailure()
1252 {
1253 }
1254
1255 public override Vector3 PIDTarget { set { return; } }
1256 public override bool PIDActive { set { return; } }
1257 public override float PIDTau { set { return; } }
1258
1259 public override float PIDHoverHeight { set { return; } }
1260 public override bool PIDHoverActive { set { return; } }
1261 public override PIDHoverType PIDHoverType { set { return; } }
1262 public override float PIDHoverTau { set { return; } }
1263
1264 public override Quaternion APIDTarget{ set { return; } }
1265
1266 public override bool APIDActive{ set { return; } }
1267
1268 public override float APIDStrength{ set { return; } }
1269
1270 public override float APIDDamping{ set { return; } }
1271
1272
1273 public override void SubscribeEvents(int ms)
1274 {
1275 m_requestedUpdateFrequency = ms;
1276 m_eventsubscription = ms;
1277 _parent_scene.addCollisionEventReporting(this);
1278 }
1279 public override void UnSubscribeEvents()
1280 {
1281 _parent_scene.remCollisionEventReporting(this);
1282 m_requestedUpdateFrequency = 0;
1283 m_eventsubscription = 0;
1284 }
1285 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1286 {
1287 if (m_eventsubscription > 0)
1288 {
1289 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
1290 }
1291 }
1292
1293 public void SendCollisions()
1294 {
1295 if (m_eventsubscription > m_requestedUpdateFrequency)
1296 {
1297 if (CollisionEventsThisFrame != null)
1298 {
1299 base.SendCollisionUpdate(CollisionEventsThisFrame);
1300 }
1301 CollisionEventsThisFrame = new CollisionEventUpdate();
1302 m_eventsubscription = 0;
1303 }
1304 }
1305 public override bool SubscribedEvents()
1306 {
1307 if (m_eventsubscription > 0)
1308 return true;
1309 return false;
1310 }
1311
1312 public void ProcessTaints(float timestep)
1313 {
1314
1315 if (m_tainted_isPhysical != m_isPhysical)
1316 {
1317 if (m_tainted_isPhysical)
1318 {
1319 // Create avatar capsule and related ODE data
1320 if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero))
1321 {
1322 m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - "
1323 + (Shell!=IntPtr.Zero ? "Shell ":"")
1324 + (Body!=IntPtr.Zero ? "Body ":"")
1325 + (Amotor!=IntPtr.Zero ? "Amotor ":""));
1326 }
1327 AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor);
1328 _parent_scene.AddCharacter(this);
1329 }
1330 else
1331 {
1332 _parent_scene.RemoveCharacter(this);
1333 // destroy avatar capsule and related ODE data
1334 if (Amotor != IntPtr.Zero)
1335 {
1336 // Kill the Amotor
1337 d.JointDestroy(Amotor);
1338 Amotor = IntPtr.Zero;
1339 }
1340 //kill the Geometry
1341 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1342
1343 if (Body != IntPtr.Zero)
1344 {
1345 //kill the body
1346 d.BodyDestroy(Body);
1347 Body = IntPtr.Zero;
1348 }
1349
1350 if(Shell != IntPtr.Zero)
1351 {
1352 try
1353 {
1354 d.GeomDestroy(Shell);
1355 }
1356 catch (System.AccessViolationException)
1357 {
1358 m_log.Error("[PHYSICS]: PrimGeom dead");
1359 }
1360 // Remove any old entries
1361//string tShell;
1362//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
1363//Console.WriteLine("**** Remove {0}", tShell);
1364
1365 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
1366 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
1367 Shell = IntPtr.Zero;
1368 }
1369 }
1370
1371 m_isPhysical = m_tainted_isPhysical;
1372 }
1373
1374 if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH)
1375 {
1376 if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1377 {
1378
1379 m_pidControllerActive = true;
1380 // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate()
1381 d.JointDestroy(Amotor);
1382 float prevCapsule = CAPSULE_LENGTH;
1383 CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
1384 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
1385 d.BodyDestroy(Body);
1386 AvatarGeomAndBodyCreation(_position.X, _position.Y,
1387 _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor);
1388 Velocity = Vector3.Zero;
1389 }
1390 else
1391 {
1392 m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - "
1393 + (Shell==IntPtr.Zero ? "Shell ":"")
1394 + (Body==IntPtr.Zero ? "Body ":"")
1395 + (Amotor==IntPtr.Zero ? "Amotor ":""));
1396 }
1397 }
1398
1399 if (!m_taintPosition.ApproxEquals(_position, 0.05f))
1400 {
1401 if (Body != IntPtr.Zero)
1402 {
1403 d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z);
1404
1405 _position.X = m_taintPosition.X;
1406 _position.Y = m_taintPosition.Y;
1407 _position.Z = m_taintPosition.Z;
1408 }
1409 }
1410
1411 }
1412
1413 internal void AddCollisionFrameTime(int p)
1414 {
1415 // protect it from overflow crashing
1416 if (m_eventsubscription + p >= int.MaxValue)
1417 m_eventsubscription = 0;
1418 m_eventsubscription += p;
1419 }
1420 }
1421}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
new file mode 100644
index 0000000..7e70db9
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
@@ -0,0 +1,3910 @@
1/* Copyright (c) Contributors, http://opensimulator.org/
2 * See CONTRIBUTORS.TXT for a full list of copyright holders.
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 * * Redistributions of source code must retain the above copyright
6 * notice, this list of conditions and the following disclaimer.
7 * * Redistributions in binary form must reproduce the above copyright
8 * notice, this list of conditions and the following disclaimer in the
9 * documentation and/or other materials provided with the distribution.
10 * * Neither the name of the OpenSimulator Project nor the
11 * names of its contributors may be used to endorse or promote products
12 * derived from this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Revised March 5th 2010 by Kitto Flora. ODEDynamics.cs
26 * rolled into ODEPrim.cs
27 */
28
29using System;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Runtime.InteropServices;
33using System.Threading;
34using log4net;
35using OpenMetaverse;
36using Ode.NET;
37using OpenSim.Framework;
38using OpenSim.Region.Physics.Manager;
39
40
41namespace OpenSim.Region.Physics.OdePlugin
42{
43 /// <summary>
44 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
45 /// </summary>
46
47 public class OdePrim : PhysicsActor
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private Vector3 _position;
52 private Vector3 _velocity;
53 private Vector3 _torque;
54 private Vector3 m_lastVelocity;
55 private Vector3 m_lastposition;
56 private Quaternion m_lastorientation = new Quaternion();
57 private Vector3 m_rotationalVelocity;
58 private Vector3 _size;
59 private Vector3 _acceleration;
60 // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f);
61 private Quaternion _orientation;
62 private Vector3 m_taintposition;
63 private Vector3 m_taintsize;
64 private Vector3 m_taintVelocity;
65 private Vector3 m_taintTorque;
66 private Quaternion m_taintrot;
67 private Vector3 m_rotateEnable = Vector3.One; // Current setting
68 private Vector3 m_rotateEnableRequest = Vector3.One; // Request from LSL
69 private bool m_rotateEnableUpdate = false;
70 private Vector3 m_lockX;
71 private Vector3 m_lockY;
72 private Vector3 m_lockZ;
73 private IntPtr Amotor = IntPtr.Zero;
74 private IntPtr AmotorX = IntPtr.Zero;
75 private IntPtr AmotorY = IntPtr.Zero;
76 private IntPtr AmotorZ = IntPtr.Zero;
77
78 private Vector3 m_PIDTarget;
79 private float m_PIDTau;
80 private float PID_D = 35f;
81 private float PID_G = 25f;
82 private bool m_usePID = false;
83
84 private Quaternion m_APIDTarget = new Quaternion();
85 private float m_APIDStrength = 0.5f;
86 private float m_APIDDamping = 0.5f;
87 private bool m_useAPID = false;
88
89 // These next 7 params apply to llSetHoverHeight(float height, integer water, float tau),
90 // do not confuse with VEHICLE HOVER
91
92 private float m_PIDHoverHeight;
93 private float m_PIDHoverTau;
94 private bool m_useHoverPID;
95 private PIDHoverType m_PIDHoverType = PIDHoverType.Ground;
96 private float m_targetHoverHeight;
97 private float m_groundHeight;
98 private float m_waterHeight;
99 private float m_buoyancy; //m_buoyancy set by llSetBuoyancy()
100
101 // private float m_tensor = 5f;
102 private int body_autodisable_frames = 20;
103
104
105 private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
106 | CollisionCategories.Space
107 | CollisionCategories.Body
108 | CollisionCategories.Character
109 );
110 private bool m_taintshape;
111 private bool m_taintPhysics;
112 private bool m_collidesLand = true;
113 private bool m_collidesWater;
114 public bool m_returnCollisions;
115
116 // Default we're a Geometry
117 private CollisionCategories m_collisionCategories = (CollisionCategories.Geom);
118
119 // Default, Collide with Other Geometries, spaces and Bodies
120 private CollisionCategories m_collisionFlags = m_default_collisionFlags;
121
122 public bool m_taintremove;
123 public bool m_taintdisable;
124 public bool m_disabled;
125 public bool m_taintadd;
126 public bool m_taintselected;
127 public bool m_taintCollidesWater;
128
129 public uint m_localID;
130
131 //public GCHandle gc;
132 private CollisionLocker ode;
133
134 private bool m_taintforce = false;
135 private bool m_taintaddangularforce = false;
136 private Vector3 m_force;
137 private List<Vector3> m_forcelist = new List<Vector3>();
138 private List<Vector3> m_angularforcelist = new List<Vector3>();
139
140 private IMesh _mesh;
141 private PrimitiveBaseShape _pbs;
142 private OdeScene _parent_scene;
143 public IntPtr m_targetSpace = IntPtr.Zero;
144 public IntPtr prim_geom;
145// public IntPtr prev_geom;
146 public IntPtr _triMeshData;
147
148 private IntPtr _linkJointGroup = IntPtr.Zero;
149 private PhysicsActor _parent;
150 private PhysicsActor m_taintparent;
151
152 private List<OdePrim> childrenPrim = new List<OdePrim>();
153
154 private bool iscolliding;
155 private bool m_isphysical;
156 private bool m_isSelected;
157
158 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
159
160 private bool m_throttleUpdates;
161 private int throttleCounter;
162 public int m_interpenetrationcount;
163 public float m_collisionscore;
164 public int m_roundsUnderMotionThreshold;
165 private int m_crossingfailures;
166
167 public bool outofBounds;
168 private float m_density = 10.000006836f; // Aluminum g/cm3;
169
170 public bool _zeroFlag; // if body has been stopped
171 private bool m_lastUpdateSent;
172
173 public IntPtr Body = IntPtr.Zero;
174 public String m_primName;
175 private Vector3 _target_velocity;
176 public d.Mass pMass;
177
178 public int m_eventsubscription;
179 private CollisionEventUpdate CollisionEventsThisFrame;
180
181 private IntPtr m_linkJoint = IntPtr.Zero;
182
183 public volatile bool childPrim;
184
185 internal int m_material = (int)Material.Wood;
186
187 private int frcount = 0; // Used to limit dynamics debug output to
188 private int revcount = 0; // Reverse motion while > 0
189
190 private IntPtr m_body = IntPtr.Zero;
191
192 // Vehicle properties ============================================================================================
193 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
194 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
195 private VehicleFlag m_flags = (VehicleFlag) 0; // Bit settings:
196 // HOVER_TERRAIN_ONLY
197 // HOVER_GLOBAL_HEIGHT
198 // NO_DEFLECTION_UP
199 // HOVER_WATER_ONLY
200 // HOVER_UP_ONLY
201 // LIMIT_MOTOR_UP
202 // LIMIT_ROLL_ONLY
203
204 // Linear properties
205 private Vector3 m_linearMotorDirection = Vector3.Zero; // (was m_linearMotorDirectionLASTSET) the (local) Velocity
206 //requested by LSL
207 private float m_linearMotorTimescale = 0; // Motor Attack rate set by LSL
208 private float m_linearMotorDecayTimescale = 0; // Motor Decay rate set by LSL
209 private Vector3 m_linearFrictionTimescale = Vector3.Zero; // General Friction set by LSL
210
211 private Vector3 m_lLinMotorDVel = Vector3.Zero; // decayed motor
212 private Vector3 m_lLinObjectVel = Vector3.Zero; // local frame object velocity
213 private Vector3 m_wLinObjectVel = Vector3.Zero; // world frame object velocity
214
215 //Angular properties
216 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
217
218 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
219 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
220 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
221
222 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
223// private Vector3 m_angObjectVel = Vector3.Zero; // current body angular velocity
224 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
225
226 //Deflection properties
227 // private float m_angularDeflectionEfficiency = 0;
228 // private float m_angularDeflectionTimescale = 0;
229 // private float m_linearDeflectionEfficiency = 0;
230 // private float m_linearDeflectionTimescale = 0;
231
232 //Banking properties
233 // private float m_bankingEfficiency = 0;
234 // private float m_bankingMix = 0;
235 // private float m_bankingTimescale = 0;
236
237 //Hover and Buoyancy properties
238 private float m_VhoverHeight = 0f;
239// private float m_VhoverEfficiency = 0f;
240 private float m_VhoverTimescale = 0f;
241 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
242 private float m_VehicleBuoyancy = 0f; // Set by VEHICLE_BUOYANCY, for a vehicle.
243 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
244 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
245 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
246
247 //Attractor properties
248 private float m_verticalAttractionEfficiency = 1.0f; // damped
249 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
250
251
252
253
254
255
256 public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
257 Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode)
258 {
259 ode = dode;
260 if (!pos.IsFinite())
261 {
262 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
263 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
264 m_log.Warn("[PHYSICS]: Got nonFinite Object create Position");
265 }
266
267 _position = pos;
268 m_taintposition = pos;
269 PID_D = parent_scene.bodyPIDD;
270 PID_G = parent_scene.bodyPIDG;
271 m_density = parent_scene.geomDefaultDensity;
272 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
273 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
274
275
276 prim_geom = IntPtr.Zero;
277// prev_geom = IntPtr.Zero;
278
279 if (!pos.IsFinite())
280 {
281 size = new Vector3(0.5f, 0.5f, 0.5f);
282 m_log.Warn("[PHYSICS]: Got nonFinite Object create Size");
283 }
284
285 if (size.X <= 0) size.X = 0.01f;
286 if (size.Y <= 0) size.Y = 0.01f;
287 if (size.Z <= 0) size.Z = 0.01f;
288
289 _size = size;
290 m_taintsize = _size;
291
292 if (!QuaternionIsFinite(rotation))
293 {
294 rotation = Quaternion.Identity;
295 m_log.Warn("[PHYSICS]: Got nonFinite Object create Rotation");
296 }
297
298 _orientation = rotation;
299 m_taintrot = _orientation;
300 _mesh = mesh;
301 _pbs = pbs;
302
303 _parent_scene = parent_scene;
304 m_targetSpace = (IntPtr)0;
305
306// if (pos.Z < 0)
307 if (pos.Z < parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y))
308 m_isphysical = false;
309 else
310 {
311 m_isphysical = pisPhysical;
312 // If we're physical, we need to be in the master space for now.
313 // linksets *should* be in a space together.. but are not currently
314 if (m_isphysical)
315 m_targetSpace = _parent_scene.space;
316 }
317 m_primName = primName;
318 m_taintadd = true;
319 _parent_scene.AddPhysicsActorTaint(this);
320 // don't do .add() here; old geoms get recycled with the same hash
321 }
322
323 public override int PhysicsActorType
324 {
325 get { return (int) ActorTypes.Prim; }
326 set { return; }
327 }
328
329 public override bool SetAlwaysRun
330 {
331 get { return false; }
332 set { return; }
333 }
334
335 public override uint LocalID
336 {
337 set {
338 //m_log.Info("[PHYSICS]: Setting TrackerID: " + value);
339 m_localID = value; }
340 }
341
342 public override bool Grabbed
343 {
344 set { return; }
345 }
346
347 public override bool Selected
348 {
349 set {
350
351//Console.WriteLine("Sel {0} {1} {2}", m_primName, value, m_isphysical);
352 // This only makes the object not collidable if the object
353 // is physical or the object is modified somehow *IN THE FUTURE*
354 // without this, if an avatar selects prim, they can walk right
355 // through it while it's selected
356 m_collisionscore = 0;
357 if ((m_isphysical && !_zeroFlag) || !value)
358 {
359 m_taintselected = value;
360 _parent_scene.AddPhysicsActorTaint(this);
361 }
362 else
363 {
364 m_taintselected = value;
365 m_isSelected = value;
366 }
367 if(m_isSelected) disableBodySoft();
368 }
369 }
370
371 public override bool IsPhysical
372 {
373 get { return m_isphysical; }
374 set
375 {
376 m_isphysical = value;
377 if (!m_isphysical)
378 { // Zero the remembered last velocity
379 m_lastVelocity = Vector3.Zero;
380 if (m_type != Vehicle.TYPE_NONE) Halt();
381 }
382 }
383 }
384
385 public void setPrimForRemoval()
386 {
387 m_taintremove = true;
388 }
389
390 public override bool Flying
391 {
392 // no flying prims for you
393 get { return false; }
394 set { }
395 }
396
397 public override bool IsColliding
398 {
399 get { return iscolliding; }
400 set { iscolliding = value; }
401 }
402
403 public override bool CollidingGround
404 {
405 get { return false; }
406 set { return; }
407 }
408
409 public override bool CollidingObj
410 {
411 get { return false; }
412 set { return; }
413 }
414
415 public override bool ThrottleUpdates
416 {
417 get { return m_throttleUpdates; }
418 set { m_throttleUpdates = value; }
419 }
420
421 public override bool Stopped
422 {
423 get { return _zeroFlag; }
424 }
425
426 public override Vector3 Position
427 {
428 get { return _position; }
429
430 set { _position = value;
431 //m_log.Info("[PHYSICS]: " + _position.ToString());
432 }
433 }
434
435 public override Vector3 Size
436 {
437 get { return _size; }
438 set
439 {
440 if (value.IsFinite())
441 {
442 _size = value;
443 }
444 else
445 {
446 m_log.Warn("[PHYSICS]: Got NaN Size on object");
447 }
448 }
449 }
450
451 public override float Mass
452 {
453 get { return CalculateMass(); }
454 }
455
456 public override Vector3 Force
457 {
458 //get { return Vector3.Zero; }
459 get { return m_force; }
460 set
461 {
462 if (value.IsFinite())
463 {
464 m_force = value;
465 }
466 else
467 {
468 m_log.Warn("[PHYSICS]: NaN in Force Applied to an Object");
469 }
470 }
471 }
472
473 public override int VehicleType
474 {
475 get { return (int)m_type; }
476 set { ProcessTypeChange((Vehicle)value); }
477 }
478
479 public override void VehicleFloatParam(int param, float value)
480 {
481 ProcessFloatVehicleParam((Vehicle) param, value);
482 }
483
484 public override void VehicleVectorParam(int param, Vector3 value)
485 {
486 ProcessVectorVehicleParam((Vehicle) param, value);
487 }
488
489 public override void VehicleRotationParam(int param, Quaternion rotation)
490 {
491 ProcessRotationVehicleParam((Vehicle) param, rotation);
492 }
493
494 public override void VehicleFlags(int param, bool remove)
495 {
496 ProcessVehicleFlags(param, remove);
497 }
498
499 public override void SetVolumeDetect(int param)
500 {
501 lock (_parent_scene.OdeLock)
502 {
503 m_isVolumeDetect = (param!=0);
504 }
505 }
506
507 public override Vector3 CenterOfMass
508 {
509 get { return Vector3.Zero; }
510 }
511
512 public override Vector3 GeometricCenter
513 {
514 get { return Vector3.Zero; }
515 }
516
517 public override PrimitiveBaseShape Shape
518 {
519 set
520 {
521 _pbs = value;
522 m_taintshape = true;
523 }
524 }
525
526 public override Vector3 Velocity
527 {
528 get
529 {
530 // Averate previous velocity with the new one so
531 // client object interpolation works a 'little' better
532 if (_zeroFlag)
533 return Vector3.Zero;
534
535 Vector3 returnVelocity = Vector3.Zero;
536 returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2;
537 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2;
538 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2;
539 return returnVelocity;
540 }
541 set
542 {
543 if (value.IsFinite())
544 {
545 _velocity = value;
546
547 m_taintVelocity = value;
548 _parent_scene.AddPhysicsActorTaint(this);
549 }
550 else
551 {
552 m_log.Warn("[PHYSICS]: Got NaN Velocity in Object");
553 }
554
555 }
556 }
557
558 public override Vector3 Torque
559 {
560 get
561 {
562 if (!m_isphysical || Body == IntPtr.Zero)
563 return Vector3.Zero;
564
565 return _torque;
566 }
567
568 set
569 {
570 if (value.IsFinite())
571 {
572 m_taintTorque = value;
573 _parent_scene.AddPhysicsActorTaint(this);
574 }
575 else
576 {
577 m_log.Warn("[PHYSICS]: Got NaN Torque in Object");
578 }
579 }
580 }
581
582 public override float CollisionScore
583 {
584 get { return m_collisionscore; }
585 set { m_collisionscore = value; }
586 }
587
588 public override bool Kinematic
589 {
590 get { return false; }
591 set { }
592 }
593
594 public override Quaternion Orientation
595 {
596 get { return _orientation; }
597 set
598 {
599 if (QuaternionIsFinite(value))
600 {
601 _orientation = value;
602 }
603 else
604 m_log.Warn("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object");
605
606 }
607 }
608
609
610 public override bool FloatOnWater
611 {
612 set {
613 m_taintCollidesWater = value;
614 _parent_scene.AddPhysicsActorTaint(this);
615 }
616 }
617
618 public override void SetMomentum(Vector3 momentum)
619 {
620 }
621
622 public override Vector3 PIDTarget
623 {
624 set
625 {
626 if (value.IsFinite())
627 {
628 m_PIDTarget = value;
629 }
630 else
631 m_log.Warn("[PHYSICS]: Got NaN PIDTarget from Scene on Object");
632 }
633 }
634 public override bool PIDActive { set { m_usePID = value; } }
635 public override float PIDTau { set { m_PIDTau = value; } }
636
637 // For RotLookAt
638 public override Quaternion APIDTarget { set { m_APIDTarget = value; } }
639 public override bool APIDActive { set { m_useAPID = value; } }
640 public override float APIDStrength { set { m_APIDStrength = value; } }
641 public override float APIDDamping { set { m_APIDDamping = value; } }
642
643 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
644 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
645 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
646 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
647
648 internal static bool QuaternionIsFinite(Quaternion q)
649 {
650 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
651 return false;
652 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
653 return false;
654 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
655 return false;
656 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
657 return false;
658 return true;
659 }
660
661 public override Vector3 Acceleration // client updates read data via here
662 {
663 get { return _acceleration; }
664 }
665
666
667 public void SetAcceleration(Vector3 accel) // No one calls this, and it would not do anything.
668 {
669 _acceleration = accel;
670 }
671
672 public override void AddForce(Vector3 force, bool pushforce)
673 {
674 if (force.IsFinite())
675 {
676 lock (m_forcelist)
677 m_forcelist.Add(force);
678
679 m_taintforce = true;
680 }
681 else
682 {
683 m_log.Warn("[PHYSICS]: Got Invalid linear force vector from Scene in Object");
684 }
685 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
686 }
687
688 public override void AddAngularForce(Vector3 force, bool pushforce)
689 {
690 if (force.IsFinite())
691 {
692 m_angularforcelist.Add(force);
693 m_taintaddangularforce = true;
694 }
695 else
696 {
697 m_log.Warn("[PHYSICS]: Got Invalid Angular force vector from Scene in Object");
698 }
699 }
700
701 public override Vector3 RotationalVelocity
702 {
703 get
704 {
705 return m_rotationalVelocity;
706 }
707 set
708 {
709 if (value.IsFinite())
710 {
711 m_rotationalVelocity = value;
712 }
713 else
714 {
715 m_log.Warn("[PHYSICS]: Got NaN RotationalVelocity in Object");
716 }
717 }
718 }
719
720 public override void CrossingFailure()
721 {
722 m_crossingfailures++;
723 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
724 {
725 base.RaiseOutOfBounds(_position);
726 return;
727 }
728 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
729 {
730 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + m_primName);
731 }
732 }
733
734 public override float Buoyancy
735 {
736 get { return m_buoyancy; }
737// set { m_buoyancy = value; }
738 set {
739 m_buoyancy = value;
740
741 Console.WriteLine("m_buoyancy={0}", m_buoyancy);
742 }
743 }
744
745 public override void link(PhysicsActor obj)
746 {
747 m_taintparent = obj;
748 }
749
750 public override void delink()
751 {
752 m_taintparent = null;
753 }
754
755 public override void LockAngularMotion(Vector3 axis)
756 {
757 // This is actually ROTATION ENABLE, not a lock.
758 // default is <1,1,1> which is all enabled.
759 // The lock value is updated inside Move(), no point in using the taint system.
760 // OS 'm_taintAngularLock' etc change to m_rotateEnable.
761 if (axis.IsFinite())
762 {
763 axis.X = (axis.X > 0) ? 1f : 0f;
764 axis.Y = (axis.Y > 0) ? 1f : 0f;
765 axis.Z = (axis.Z > 0) ? 1f : 0f;
766 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
767 m_rotateEnableRequest = axis;
768 m_rotateEnableUpdate = true;
769 }
770 else
771 {
772 m_log.Warn("[PHYSICS]: Got NaN locking axis from Scene on Object");
773 }
774 }
775
776
777 public void SetGeom(IntPtr geom)
778 {
779 if(prim_geom != IntPtr.Zero)
780 {
781 // Remove any old entries
782//string tPA;
783//_parent_scene.geom_name_map.TryGetValue(prim_geom, out tPA);
784//Console.WriteLine("**** Remove {0}", tPA);
785 if(_parent_scene.geom_name_map.ContainsKey(prim_geom)) _parent_scene.geom_name_map.Remove(prim_geom);
786 if(_parent_scene.actor_name_map.ContainsKey(prim_geom)) _parent_scene.actor_name_map.Remove(prim_geom);
787 d.GeomDestroy(prim_geom);
788 }
789
790 prim_geom = geom;
791//Console.WriteLine("SetGeom to " + prim_geom + " for " + m_primName);
792 if (prim_geom != IntPtr.Zero)
793 {
794 _parent_scene.geom_name_map[prim_geom] = this.m_primName;
795 _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
796 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
797 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
798//Console.WriteLine("**** Create {2} Dicts: actor={0} name={1}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, this.m_primName);
799 }
800
801 if (childPrim)
802 {
803 if (_parent != null && _parent is OdePrim)
804 {
805 OdePrim parent = (OdePrim)_parent;
806//Console.WriteLine("SetGeom calls ChildSetGeom");
807 parent.ChildSetGeom(this);
808 }
809 }
810 //m_log.Warn("Setting Geom to: " + prim_geom);
811 }
812
813 public void enableBodySoft()
814 {
815 if (!childPrim)
816 {
817 if (m_isphysical && Body != IntPtr.Zero)
818 {
819 d.BodyEnable(Body);
820 if (m_type != Vehicle.TYPE_NONE)
821 Enable(Body, _parent_scene);
822 }
823
824 m_disabled = false;
825 }
826 }
827
828 public void disableBodySoft()
829 {
830 m_disabled = true;
831
832 if (m_isphysical && Body != IntPtr.Zero)
833 {
834 d.BodyDisable(Body);
835 Halt();
836 }
837 }
838
839 public void enableBody()
840 {
841 // Don't enable this body if we're a child prim
842 // this should be taken care of in the parent function not here
843 if (!childPrim)
844 {
845 // Sets the geom to a body
846 Body = d.BodyCreate(_parent_scene.world);
847
848 setMass();
849 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
850 d.Quaternion myrot = new d.Quaternion();
851 myrot.X = _orientation.X;
852 myrot.Y = _orientation.Y;
853 myrot.Z = _orientation.Z;
854 myrot.W = _orientation.W;
855 d.BodySetQuaternion(Body, ref myrot);
856 d.GeomSetBody(prim_geom, Body);
857 m_collisionCategories |= CollisionCategories.Body;
858 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
859
860 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
861 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
862
863 d.BodySetAutoDisableFlag(Body, true);
864 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
865
866 // disconnect from world gravity so we can apply buoyancy
867 d.BodySetGravityMode (Body, false);
868
869 m_interpenetrationcount = 0;
870 m_collisionscore = 0;
871 m_disabled = false;
872
873 if (m_type != Vehicle.TYPE_NONE)
874 {
875 Enable(Body, _parent_scene);
876 }
877
878 _parent_scene.addActivePrim(this);
879 }
880 }
881
882 #region Mass Calculation
883
884 private float CalculateMass()
885 {
886 float volume = 0;
887
888 // No material is passed to the physics engines yet.. soo..
889 // we're using the m_density constant in the class definition
890
891 float returnMass = 0;
892
893 switch (_pbs.ProfileShape)
894 {
895 case ProfileShape.Square:
896 // Profile Volume
897
898 volume = _size.X*_size.Y*_size.Z;
899
900 // If the user has 'hollowed out'
901 // ProfileHollow is one of those 0 to 50000 values :P
902 // we like percentages better.. so turning into a percentage
903
904 if (((float) _pbs.ProfileHollow/50000f) > 0.0)
905 {
906 float hollowAmount = (float) _pbs.ProfileHollow/50000f;
907
908 // calculate the hollow volume by it's shape compared to the prim shape
909 float hollowVolume = 0;
910 switch (_pbs.HollowShape)
911 {
912 case HollowShape.Square:
913 case HollowShape.Same:
914 // Cube Hollow volume calculation
915 float hollowsizex = _size.X*hollowAmount;
916 float hollowsizey = _size.Y*hollowAmount;
917 float hollowsizez = _size.Z*hollowAmount;
918 hollowVolume = hollowsizex*hollowsizey*hollowsizez;
919 break;
920
921 case HollowShape.Circle:
922 // Hollow shape is a perfect cyllinder in respect to the cube's scale
923 // Cyllinder hollow volume calculation
924 float hRadius = _size.X/2;
925 float hLength = _size.Z;
926
927 // pi * r2 * h
928 hollowVolume = ((float) (Math.PI*Math.Pow(hRadius, 2)*hLength)*hollowAmount);
929 break;
930
931 case HollowShape.Triangle:
932 // Equilateral Triangular Prism volume hollow calculation
933 // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
934
935 float aLength = _size.Y;
936 // 1/2 abh
937 hollowVolume = (float) ((0.5*aLength*_size.X*_size.Z)*hollowAmount);
938 break;
939
940 default:
941 hollowVolume = 0;
942 break;
943 }
944 volume = volume - hollowVolume;
945 }
946
947 break;
948 case ProfileShape.Circle:
949 if (_pbs.PathCurve == (byte)Extrusion.Straight)
950 {
951 // Cylinder
952 float volume1 = (float)(Math.PI * Math.Pow(_size.X/2, 2) * _size.Z);
953 float volume2 = (float)(Math.PI * Math.Pow(_size.Y/2, 2) * _size.Z);
954
955 // Approximating the cylinder's irregularity.
956 if (volume1 > volume2)
957 {
958 volume = (float)volume1 - (volume1 - volume2);
959 }
960 else if (volume2 > volume1)
961 {
962 volume = (float)volume2 - (volume2 - volume1);
963 }
964 else
965 {
966 // Regular cylinder
967 volume = volume1;
968 }
969 }
970 else
971 {
972 // We don't know what the shape is yet, so use default
973 volume = _size.X * _size.Y * _size.Z;
974 }
975 // If the user has 'hollowed out'
976 // ProfileHollow is one of those 0 to 50000 values :P
977 // we like percentages better.. so turning into a percentage
978
979 if (((float)_pbs.ProfileHollow / 50000f) > 0.0)
980 {
981 float hollowAmount = (float)_pbs.ProfileHollow / 50000f;
982
983 // calculate the hollow volume by it's shape compared to the prim shape
984 float hollowVolume = 0;
985 switch (_pbs.HollowShape)
986 {
987 case HollowShape.Same:
988 case HollowShape.Circle:
989 // Hollow shape is a perfect cyllinder in respect to the cube's scale
990 // Cyllinder hollow volume calculation
991 float hRadius = _size.X / 2;
992 float hLength = _size.Z;
993
994 // pi * r2 * h
995 hollowVolume = ((float)(Math.PI * Math.Pow(hRadius, 2) * hLength) * hollowAmount);
996 break;
997
998 case HollowShape.Square:
999 // Cube Hollow volume calculation
1000 float hollowsizex = _size.X * hollowAmount;
1001 float hollowsizey = _size.Y * hollowAmount;
1002 float hollowsizez = _size.Z * hollowAmount;
1003 hollowVolume = hollowsizex * hollowsizey * hollowsizez;
1004 break;
1005
1006 case HollowShape.Triangle:
1007 // Equilateral Triangular Prism volume hollow calculation
1008 // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
1009
1010 float aLength = _size.Y;
1011 // 1/2 abh
1012 hollowVolume = (float)((0.5 * aLength * _size.X * _size.Z) * hollowAmount);
1013 break;
1014
1015 default:
1016 hollowVolume = 0;
1017 break;
1018 }
1019 volume = volume - hollowVolume;
1020 }
1021 break;
1022
1023 case ProfileShape.HalfCircle:
1024 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1025 {
1026 if (_size.X == _size.Y && _size.Y == _size.Z)
1027 {
1028 // regular sphere
1029 // v = 4/3 * pi * r^3
1030 float sradius3 = (float)Math.Pow((_size.X / 2), 3);
1031 volume = (float)((4f / 3f) * Math.PI * sradius3);
1032 }
1033 else
1034 {
1035 // we treat this as a box currently
1036 volume = _size.X * _size.Y * _size.Z;
1037 }
1038 }
1039 else
1040 {
1041 // We don't know what the shape is yet, so use default
1042 volume = _size.X * _size.Y * _size.Z;
1043 }
1044 break;
1045
1046 case ProfileShape.EquilateralTriangle:
1047 /*
1048 v = (abs((xB*yA-xA*yB)+(xC*yB-xB*yC)+(xA*yC-xC*yA))/2) * h
1049
1050 // seed mesh
1051 Vertex MM = new Vertex(-0.25f, -0.45f, 0.0f);
1052 Vertex PM = new Vertex(+0.5f, 0f, 0.0f);
1053 Vertex PP = new Vertex(-0.25f, +0.45f, 0.0f);
1054 */
1055 float xA = -0.25f * _size.X;
1056 float yA = -0.45f * _size.Y;
1057
1058 float xB = 0.5f * _size.X;
1059 float yB = 0;
1060
1061 float xC = -0.25f * _size.X;
1062 float yC = 0.45f * _size.Y;
1063
1064 volume = (float)((Math.Abs((xB * yA - xA * yB) + (xC * yB - xB * yC) + (xA * yC - xC * yA)) / 2) * _size.Z);
1065
1066 // If the user has 'hollowed out'
1067 // ProfileHollow is one of those 0 to 50000 values :P
1068 // we like percentages better.. so turning into a percentage
1069 float fhollowFactor = ((float)_pbs.ProfileHollow / 1.9f);
1070 if (((float)fhollowFactor / 50000f) > 0.0)
1071 {
1072 float hollowAmount = (float)fhollowFactor / 50000f;
1073
1074 // calculate the hollow volume by it's shape compared to the prim shape
1075 float hollowVolume = 0;
1076 switch (_pbs.HollowShape)
1077 {
1078 case HollowShape.Same:
1079 case HollowShape.Triangle:
1080 // Equilateral Triangular Prism volume hollow calculation
1081 // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
1082
1083 float aLength = _size.Y;
1084 // 1/2 abh
1085 hollowVolume = (float)((0.5 * aLength * _size.X * _size.Z) * hollowAmount);
1086 break;
1087
1088 case HollowShape.Square:
1089 // Cube Hollow volume calculation
1090 float hollowsizex = _size.X * hollowAmount;
1091 float hollowsizey = _size.Y * hollowAmount;
1092 float hollowsizez = _size.Z * hollowAmount;
1093 hollowVolume = hollowsizex * hollowsizey * hollowsizez;
1094 break;
1095
1096 case HollowShape.Circle:
1097 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1098 // Cyllinder hollow volume calculation
1099 float hRadius = _size.X / 2;
1100 float hLength = _size.Z;
1101
1102 // pi * r2 * h
1103 hollowVolume = ((float)((Math.PI * Math.Pow(hRadius, 2) * hLength)/2) * hollowAmount);
1104 break;
1105
1106 default:
1107 hollowVolume = 0;
1108 break;
1109 }
1110 volume = volume - hollowVolume;
1111 }
1112 break;
1113
1114 default:
1115 // we don't have all of the volume formulas yet so
1116 // use the common volume formula for all
1117 volume = _size.X*_size.Y*_size.Z;
1118 break;
1119 }
1120
1121 // Calculate Path cut effect on volume
1122 // Not exact, in the triangle hollow example
1123 // They should never be zero or less then zero..
1124 // we'll ignore it if it's less then zero
1125
1126 // ProfileEnd and ProfileBegin are values
1127 // from 0 to 50000
1128
1129 // Turning them back into percentages so that I can cut that percentage off the volume
1130
1131 float PathCutEndAmount = _pbs.ProfileEnd;
1132 float PathCutStartAmount = _pbs.ProfileBegin;
1133 if (((PathCutStartAmount + PathCutEndAmount)/50000f) > 0.0f)
1134 {
1135 float pathCutAmount = ((PathCutStartAmount + PathCutEndAmount)/50000f);
1136
1137 // Check the return amount for sanity
1138 if (pathCutAmount >= 0.99f)
1139 pathCutAmount = 0.99f;
1140
1141 volume = volume - (volume*pathCutAmount);
1142 }
1143 UInt16 taperX = _pbs.PathScaleX;
1144 UInt16 taperY = _pbs.PathScaleY;
1145 float taperFactorX = 0;
1146 float taperFactorY = 0;
1147
1148 // Mass = density * volume
1149 if (taperX != 100)
1150 {
1151 if (taperX > 100)
1152 {
1153 taperFactorX = 1.0f - ((float)taperX / 200);
1154 //m_log.Warn("taperTopFactorX: " + extr.taperTopFactorX.ToString());
1155 }
1156 else
1157 {
1158 taperFactorX = 1.0f - ((100 - (float)taperX) / 100);
1159 //m_log.Warn("taperBotFactorX: " + extr.taperBotFactorX.ToString());
1160 }
1161 volume = (float)volume * ((taperFactorX / 3f) + 0.001f);
1162 }
1163
1164 if (taperY != 100)
1165 {
1166 if (taperY > 100)
1167 {
1168 taperFactorY = 1.0f - ((float)taperY / 200);
1169 //m_log.Warn("taperTopFactorY: " + extr.taperTopFactorY.ToString());
1170 }
1171 else
1172 {
1173 taperFactorY = 1.0f - ((100 - (float)taperY) / 100);
1174 //m_log.Warn("taperBotFactorY: " + extr.taperBotFactorY.ToString());
1175 }
1176 volume = (float)volume * ((taperFactorY / 3f) + 0.001f);
1177 }
1178 returnMass = m_density*volume;
1179 if (returnMass <= 0) returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
1180
1181
1182
1183 // Recursively calculate mass
1184 bool HasChildPrim = false;
1185 lock (childrenPrim)
1186 {
1187 if (childrenPrim.Count > 0)
1188 {
1189 HasChildPrim = true;
1190 }
1191
1192 }
1193 if (HasChildPrim)
1194 {
1195 OdePrim[] childPrimArr = new OdePrim[0];
1196
1197 lock (childrenPrim)
1198 childPrimArr = childrenPrim.ToArray();
1199
1200 for (int i = 0; i < childPrimArr.Length; i++)
1201 {
1202 if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove)
1203 returnMass += childPrimArr[i].CalculateMass();
1204 // failsafe, this shouldn't happen but with OpenSim, you never know :)
1205 if (i > 256)
1206 break;
1207 }
1208 }
1209 if (returnMass > _parent_scene.maximumMassObject)
1210 returnMass = _parent_scene.maximumMassObject;
1211 return returnMass;
1212 }// end CalculateMass
1213
1214 #endregion
1215
1216 public void setMass()
1217 {
1218 if (Body != (IntPtr) 0)
1219 {
1220 float newmass = CalculateMass();
1221
1222 //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString());
1223
1224 d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z);
1225 d.BodySetMass(Body, ref pMass);
1226 }
1227 }
1228
1229 public void disableBody()
1230 {
1231 //this kills the body so things like 'mesh' can re-create it.
1232 lock (this)
1233 {
1234 if (!childPrim)
1235 {
1236 if (Body != IntPtr.Zero)
1237 {
1238 _parent_scene.remActivePrim(this);
1239 m_collisionCategories &= ~CollisionCategories.Body;
1240 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1241
1242 if (prim_geom != IntPtr.Zero)
1243 {
1244 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1245 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1246 }
1247
1248
1249 d.BodyDestroy(Body);
1250 lock (childrenPrim)
1251 {
1252 if (childrenPrim.Count > 0)
1253 {
1254 foreach (OdePrim prm in childrenPrim)
1255 {
1256 _parent_scene.remActivePrim(prm);
1257 prm.Body = IntPtr.Zero;
1258 }
1259 }
1260 }
1261 Body = IntPtr.Zero;
1262 }
1263 }
1264 else
1265 {
1266 _parent_scene.remActivePrim(this);
1267
1268 m_collisionCategories &= ~CollisionCategories.Body;
1269 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1270
1271 if (prim_geom != IntPtr.Zero)
1272 {
1273 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1274 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1275 }
1276
1277
1278 Body = IntPtr.Zero;
1279 }
1280 }
1281 m_disabled = true;
1282 m_collisionscore = 0;
1283 }
1284
1285 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
1286
1287 public void setMesh(OdeScene parent_scene, IMesh mesh)
1288 {
1289 // This sleeper is there to moderate how long it takes between
1290 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
1291
1292 //Thread.Sleep(10);
1293
1294 //Kill Body so that mesh can re-make the geom
1295 if (IsPhysical && Body != IntPtr.Zero)
1296 {
1297 if (childPrim)
1298 {
1299 if (_parent != null)
1300 {
1301 OdePrim parent = (OdePrim)_parent;
1302 parent.ChildDelink(this);
1303 }
1304 }
1305 else
1306 {
1307 disableBody();
1308 }
1309 }
1310
1311 IntPtr vertices, indices;
1312 int vertexCount, indexCount;
1313 int vertexStride, triStride;
1314 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
1315 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
1316
1317 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
1318 if (m_MeshToTriMeshMap.ContainsKey(mesh))
1319 {
1320 _triMeshData = m_MeshToTriMeshMap[mesh];
1321 }
1322 else
1323 {
1324 _triMeshData = d.GeomTriMeshDataCreate();
1325
1326 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
1327 d.GeomTriMeshDataPreprocess(_triMeshData);
1328 m_MeshToTriMeshMap[mesh] = _triMeshData;
1329 }
1330
1331 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1332 try
1333 {
1334 if (prim_geom == IntPtr.Zero)
1335 {
1336 SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null));
1337 }
1338 }
1339 catch (AccessViolationException)
1340 {
1341 m_log.Error("[PHYSICS]: MESH LOCKED");
1342 return;
1343 }
1344
1345
1346 // if (IsPhysical && Body == (IntPtr) 0)
1347 // {
1348 // Recreate the body
1349 // m_interpenetrationcount = 0;
1350 // m_collisionscore = 0;
1351
1352 // enableBody();
1353 // }
1354 }
1355
1356 public void ProcessTaints(float timestep) //=============================================================================
1357 {
1358 if (m_taintadd)
1359 {
1360 changeadd(timestep);
1361 }
1362
1363 if (prim_geom != IntPtr.Zero)
1364 {
1365 if (!_position.ApproxEquals(m_taintposition, 0f))
1366 changemove(timestep);
1367
1368 if (m_taintrot != _orientation)
1369 {
1370 if(childPrim && IsPhysical) // For physical child prim...
1371 {
1372 rotate(timestep);
1373 // KF: ODE will also rotate the parent prim!
1374 // so rotate the root back to where it was
1375 OdePrim parent = (OdePrim)_parent;
1376 parent.rotate(timestep);
1377 }
1378 else
1379 {
1380 //Just rotate the prim
1381 rotate(timestep);
1382 }
1383 }
1384 //
1385
1386 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent))
1387 changePhysicsStatus(timestep);
1388 //
1389
1390 if (!_size.ApproxEquals(m_taintsize,0f))
1391 changesize(timestep);
1392 //
1393
1394 if (m_taintshape)
1395 changeshape(timestep);
1396 //
1397
1398 if (m_taintforce)
1399 changeAddForce(timestep);
1400
1401 if (m_taintaddangularforce)
1402 changeAddAngularForce(timestep);
1403
1404 if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f))
1405 changeSetTorque(timestep);
1406
1407 if (m_taintdisable)
1408 changedisable(timestep);
1409
1410 if (m_taintselected != m_isSelected)
1411 changeSelectedStatus(timestep);
1412
1413 if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f))
1414 changevelocity(timestep);
1415
1416 if (m_taintparent != _parent)
1417 changelink(timestep);
1418
1419 if (m_taintCollidesWater != m_collidesWater)
1420 changefloatonwater(timestep);
1421/* obsolete
1422 if (!m_angularLock.ApproxEquals(m_taintAngularLock,0f))
1423 changeAngularLock(timestep);
1424 */
1425 }
1426 else
1427 {
1428 m_log.Error("[PHYSICS]: The scene reused a disposed PhysActor! *waves finger*, Don't be evil. A couple of things can cause this. An improper prim breakdown(be sure to set prim_geom to zero after d.GeomDestroy! An improper buildup (creating the geom failed). Or, the Scene Reused a physics actor after disposing it.)");
1429 }
1430 }
1431
1432/* obsolete
1433 private void changeAngularLock(float timestep)
1434 {
1435 if (_parent == null)
1436 {
1437 m_angularLock = m_taintAngularLock;
1438 m_angularLockSet = true;
1439 }
1440 }
1441 */
1442 private void changelink(float timestep)
1443 {
1444 // If the newly set parent is not null
1445 // create link
1446 if (_parent == null && m_taintparent != null)
1447 {
1448 if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim)
1449 {
1450 OdePrim obj = (OdePrim)m_taintparent;
1451 //obj.disableBody();
1452 obj.ParentPrim(this);
1453
1454 /*
1455 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
1456 {
1457 _linkJointGroup = d.JointGroupCreate(0);
1458 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1459 d.JointAttach(m_linkJoint, obj.Body, Body);
1460 d.JointSetFixed(m_linkJoint);
1461 }
1462 */
1463 }
1464 }
1465 // If the newly set parent is null
1466 // destroy link
1467 else if (_parent != null && m_taintparent == null)
1468 {
1469 if (_parent is OdePrim)
1470 {
1471 OdePrim obj = (OdePrim)_parent;
1472 obj.ChildDelink(this);
1473 childPrim = false;
1474 //_parent = null;
1475 }
1476
1477 /*
1478 if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0)
1479 d.JointGroupDestroy(_linkJointGroup);
1480
1481 _linkJointGroup = (IntPtr)0;
1482 m_linkJoint = (IntPtr)0;
1483 */
1484 }
1485
1486 _parent = m_taintparent;
1487 m_taintPhysics = m_isphysical;
1488 }
1489
1490 // I'm the parent
1491 // prim is the child
1492 public void ParentPrim(OdePrim prim)
1493 {
1494 if (this.m_localID != prim.m_localID)
1495 {
1496 if (Body == IntPtr.Zero)
1497 {
1498 Body = d.BodyCreate(_parent_scene.world);
1499 setMass();
1500 }
1501 if (Body != IntPtr.Zero)
1502 {
1503 lock (childrenPrim)
1504 {
1505 if (!childrenPrim.Contains(prim))
1506 {
1507 childrenPrim.Add(prim);
1508
1509 foreach (OdePrim prm in childrenPrim)
1510 {
1511 d.Mass m2;
1512 d.MassSetZero(out m2);
1513 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1514
1515
1516 d.Quaternion quat = new d.Quaternion();
1517 quat.W = prm._orientation.W;
1518 quat.X = prm._orientation.X;
1519 quat.Y = prm._orientation.Y;
1520 quat.Z = prm._orientation.Z;
1521
1522 d.Matrix3 mat = new d.Matrix3();
1523 d.RfromQ(out mat, ref quat);
1524 d.MassRotate(ref m2, ref mat);
1525 d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z);
1526 d.MassAdd(ref pMass, ref m2);
1527 }
1528 foreach (OdePrim prm in childrenPrim)
1529 {
1530
1531 prm.m_collisionCategories |= CollisionCategories.Body;
1532 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1533
1534 if (prm.prim_geom == IntPtr.Zero)
1535 {
1536 m_log.Warn("[PHYSICS]: Unable to link one of the linkset elements. No geom yet");
1537 continue;
1538 }
1539//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + m_primName);
1540 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1541 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1542
1543
1544 d.Quaternion quat = new d.Quaternion();
1545 quat.W = prm._orientation.W;
1546 quat.X = prm._orientation.X;
1547 quat.Y = prm._orientation.Y;
1548 quat.Z = prm._orientation.Z;
1549
1550 d.Matrix3 mat = new d.Matrix3();
1551 d.RfromQ(out mat, ref quat);
1552 if (Body != IntPtr.Zero)
1553 {
1554 d.GeomSetBody(prm.prim_geom, Body);
1555 prm.childPrim = true;
1556 d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z);
1557 //d.GeomSetOffsetPosition(prim.prim_geom,
1558 // (Position.X - prm.Position.X) - pMass.c.X,
1559 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1560 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1561 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat);
1562 //d.GeomSetOffsetRotation(prm.prim_geom, ref mat);
1563 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1564 d.BodySetMass(Body, ref pMass);
1565 }
1566 else
1567 {
1568 m_log.Debug("[PHYSICS]:I ain't got no boooooooooddy, no body");
1569 }
1570
1571
1572 prm.m_interpenetrationcount = 0;
1573 prm.m_collisionscore = 0;
1574 prm.m_disabled = false;
1575
1576 prm.Body = Body;
1577 _parent_scene.addActivePrim(prm);
1578 }
1579 m_collisionCategories |= CollisionCategories.Body;
1580 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1581
1582//Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + m_primName);
1583 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1584//Console.WriteLine(" Post GeomSetCategoryBits 2");
1585 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1586
1587
1588 d.Quaternion quat2 = new d.Quaternion();
1589 quat2.W = _orientation.W;
1590 quat2.X = _orientation.X;
1591 quat2.Y = _orientation.Y;
1592 quat2.Z = _orientation.Z;
1593
1594 d.Matrix3 mat2 = new d.Matrix3();
1595 d.RfromQ(out mat2, ref quat2);
1596 d.GeomSetBody(prim_geom, Body);
1597 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1598 //d.GeomSetOffsetPosition(prim.prim_geom,
1599 // (Position.X - prm.Position.X) - pMass.c.X,
1600 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1601 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1602 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1603 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1604 d.BodySetMass(Body, ref pMass);
1605
1606 d.BodySetAutoDisableFlag(Body, true);
1607 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1608
1609
1610 m_interpenetrationcount = 0;
1611 m_collisionscore = 0;
1612 m_disabled = false;
1613
1614 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1615 if (m_type != Vehicle.TYPE_NONE) Enable(Body, _parent_scene);
1616 _parent_scene.addActivePrim(this);
1617 }
1618 }
1619 }
1620 }
1621
1622 }
1623
1624 private void ChildSetGeom(OdePrim odePrim)
1625 {
1626 //if (m_isphysical && Body != IntPtr.Zero)
1627 lock (childrenPrim)
1628 {
1629 foreach (OdePrim prm in childrenPrim)
1630 {
1631 //prm.childPrim = true;
1632 prm.disableBody();
1633 //prm.m_taintparent = null;
1634 //prm._parent = null;
1635 //prm.m_taintPhysics = false;
1636 //prm.m_disabled = true;
1637 //prm.childPrim = false;
1638 }
1639 }
1640 disableBody();
1641
1642
1643 if (Body != IntPtr.Zero)
1644 {
1645 _parent_scene.remActivePrim(this);
1646 }
1647
1648 lock (childrenPrim)
1649 {
1650 foreach (OdePrim prm in childrenPrim)
1651 {
1652 ParentPrim(prm);
1653 }
1654 }
1655
1656 }
1657
1658 private void ChildDelink(OdePrim odePrim)
1659 {
1660 // Okay, we have a delinked child.. need to rebuild the body.
1661 lock (childrenPrim)
1662 {
1663 foreach (OdePrim prm in childrenPrim)
1664 {
1665 prm.childPrim = true;
1666 prm.disableBody();
1667 //prm.m_taintparent = null;
1668 //prm._parent = null;
1669 //prm.m_taintPhysics = false;
1670 //prm.m_disabled = true;
1671 //prm.childPrim = false;
1672 }
1673 }
1674 disableBody();
1675
1676 lock (childrenPrim)
1677 {
1678 childrenPrim.Remove(odePrim);
1679 }
1680
1681 if (Body != IntPtr.Zero)
1682 {
1683 _parent_scene.remActivePrim(this);
1684 }
1685
1686 lock (childrenPrim)
1687 {
1688 foreach (OdePrim prm in childrenPrim)
1689 {
1690 ParentPrim(prm);
1691 }
1692 }
1693 }
1694
1695 private void changeSelectedStatus(float timestep)
1696 {
1697 if (m_taintselected)
1698 {
1699 m_collisionCategories = CollisionCategories.Selected;
1700 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1701
1702 // We do the body disable soft twice because 'in theory' a collision could have happened
1703 // in between the disabling and the collision properties setting
1704 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1705 // through the ground.
1706
1707 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1708 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1709 // so that causes the selected part to wake up and continue moving.
1710
1711 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1712 // assembly will stop simulating during the selection, because of the lack of atomicity
1713 // of select operations (their processing could be interrupted by a thread switch, causing
1714 // simulation to continue before all of the selected object notifications trickle down to
1715 // the physics engine).
1716
1717 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1718 // selected and disabled. then, due to a thread switch, the selection processing is
1719 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1720 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1721 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1722 // up, start simulating again, which in turn wakes up the last 50.
1723
1724 if (m_isphysical)
1725 {
1726 disableBodySoft();
1727 }
1728
1729 if (prim_geom != IntPtr.Zero)
1730 {
1731 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1732 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1733 }
1734
1735 if (m_isphysical)
1736 {
1737 disableBodySoft();
1738
1739 if (Body != IntPtr.Zero)
1740 {
1741 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1742 d.BodySetForce(Body, 0, 0, 0);
1743 enableBodySoft();
1744 }
1745 }
1746 }
1747 else
1748 {
1749 m_collisionCategories = CollisionCategories.Geom;
1750
1751 if (m_isphysical)
1752 m_collisionCategories |= CollisionCategories.Body;
1753
1754 m_collisionFlags = m_default_collisionFlags;
1755
1756 if (m_collidesLand)
1757 m_collisionFlags |= CollisionCategories.Land;
1758 if (m_collidesWater)
1759 m_collisionFlags |= CollisionCategories.Water;
1760
1761 if (prim_geom != IntPtr.Zero)
1762 {
1763 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1764 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1765 }
1766/* Uhhh - stop the motion if the object is _selected_!!
1767 if (m_isphysical)
1768 {
1769 if (Body != IntPtr.Zero)
1770 {
1771 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1772 d.BodySetForce(Body, 0, 0, 0);
1773 enableBodySoft();
1774 }
1775 }
1776*/
1777 }
1778
1779 resetCollisionAccounting();
1780 m_isSelected = m_taintselected;
1781 }//end changeSelectedStatus
1782
1783 public void ResetTaints()
1784 {
1785 m_taintposition = _position;
1786 m_taintrot = _orientation;
1787 m_taintPhysics = m_isphysical;
1788 m_taintselected = m_isSelected;
1789 m_taintsize = _size;
1790 m_taintshape = false;
1791 m_taintforce = false;
1792 m_taintdisable = false;
1793 m_taintVelocity = Vector3.Zero;
1794 }
1795
1796 public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh)
1797 {
1798//Console.WriteLine("CreateGeom:");
1799 if (_mesh != null) // Special - make mesh
1800 {
1801 setMesh(_parent_scene, _mesh);
1802 }
1803 else // not a mesh
1804 {
1805 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) // special profile??
1806 {
1807 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) // Equi-size
1808 {
1809 if (((_size.X / 2f) > 0f)) // Has size
1810 {
1811 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1812 try
1813 {
1814//Console.WriteLine(" CreateGeom 1");
1815 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1816 }
1817 catch (AccessViolationException)
1818 {
1819 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1820 ode.dunlock(_parent_scene.world);
1821 return;
1822 }
1823 }
1824 else
1825 {
1826 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1827 try
1828 {
1829//Console.WriteLine(" CreateGeom 2");
1830 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1831 }
1832 catch (AccessViolationException)
1833 {
1834 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1835 ode.dunlock(_parent_scene.world);
1836 return;
1837 }
1838 }
1839 }
1840 else // not equi-size
1841 {
1842 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1843 try
1844 {
1845//Console.WriteLine(" CreateGeom 3");
1846 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1847 }
1848 catch (AccessViolationException)
1849 {
1850 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1851 ode.dunlock(_parent_scene.world);
1852 return;
1853 }
1854 }
1855 }
1856
1857 else // not special profile
1858 {
1859 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1860 try
1861 {
1862//Console.WriteLine(" CreateGeom 4");
1863 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1864 }
1865 catch (AccessViolationException)
1866 {
1867 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1868 ode.dunlock(_parent_scene.world);
1869 return;
1870 }
1871 }
1872 }
1873 }
1874
1875 public void changeadd(float timestep)
1876 {
1877 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1878 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1879
1880 if (targetspace == IntPtr.Zero)
1881 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1882
1883 m_targetSpace = targetspace;
1884
1885 if (_mesh == null)
1886 {
1887 if (_parent_scene.needsMeshing(_pbs))
1888 {
1889 // Don't need to re-enable body.. it's done in SetMesh
1890 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1891 // createmesh returns null when it's a shape that isn't a cube.
1892 // m_log.Debug(m_localID);
1893 }
1894 }
1895
1896
1897 lock (_parent_scene.OdeLock)
1898 {
1899//Console.WriteLine("changeadd 1");
1900 CreateGeom(m_targetSpace, _mesh);
1901
1902 if (prim_geom != IntPtr.Zero)
1903 {
1904 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1905 d.Quaternion myrot = new d.Quaternion();
1906 myrot.X = _orientation.X;
1907 myrot.Y = _orientation.Y;
1908 myrot.Z = _orientation.Z;
1909 myrot.W = _orientation.W;
1910 d.GeomSetQuaternion(prim_geom, ref myrot);
1911 }
1912
1913 if (m_isphysical && Body == IntPtr.Zero)
1914 {
1915 enableBody();
1916 }
1917 }
1918
1919 changeSelectedStatus(timestep);
1920
1921 m_taintadd = false;
1922 }
1923
1924 public void changemove(float timestep)
1925 {
1926//Console.WriteLine("changemove sing/root {0} to {1}", m_primName, _position );
1927 if (m_isphysical)
1928 {
1929//Console.WriteLine("phys {0} {1} {2}", m_disabled, m_taintremove, childPrim);
1930// if (!m_disabled && !m_taintremove && !childPrim) After one edit m_disabled is sometimes set, disabling further edits!
1931 if (!m_taintremove && !childPrim)
1932 {
1933 if (Body == IntPtr.Zero)
1934 enableBody();
1935 //Prim auto disable after 20 frames,
1936 //if you move it, re-enable the prim manually.
1937 if (_parent != null)
1938 {
1939 if (m_linkJoint != IntPtr.Zero)
1940 {
1941 d.JointDestroy(m_linkJoint);
1942 m_linkJoint = IntPtr.Zero;
1943 }
1944 }
1945 if (Body != IntPtr.Zero)
1946 {
1947 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1948
1949 if (_parent != null)
1950 {
1951 OdePrim odParent = (OdePrim)_parent;
1952 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1953 {
1954// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1955Console.WriteLine(" JointCreateFixed");
1956 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1957 d.JointAttach(m_linkJoint, Body, odParent.Body);
1958 d.JointSetFixed(m_linkJoint);
1959 }
1960 }
1961 d.BodyEnable(Body);
1962 if (m_type != Vehicle.TYPE_NONE)
1963 {
1964 Enable(Body, _parent_scene);
1965 }
1966 }
1967 else
1968 {
1969 m_log.Warn("[PHYSICS]: Body Still null after enableBody(). This is a crash scenario.");
1970 }
1971 }
1972 //else
1973 // {
1974 //m_log.Debug("[BUG]: race!");
1975 //}
1976 }
1977 else
1978 {
1979 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1980 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1981 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1982
1983 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1984 m_targetSpace = tempspace;
1985
1986 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1987 if (prim_geom != IntPtr.Zero)
1988 {
1989 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1990
1991 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1992 d.SpaceAdd(m_targetSpace, prim_geom);
1993 }
1994 }
1995
1996 changeSelectedStatus(timestep);
1997
1998 resetCollisionAccounting();
1999 m_taintposition = _position;
2000 }
2001
2002
2003
2004 public void rotate(float timestep)
2005 {
2006 d.Quaternion myrot = new d.Quaternion();
2007 myrot.X = _orientation.X;
2008 myrot.Y = _orientation.Y;
2009 myrot.Z = _orientation.Z;
2010 myrot.W = _orientation.W;
2011 if (Body != IntPtr.Zero)
2012 {
2013 // KF: If this is a root prim do BodySet
2014 d.BodySetQuaternion(Body, ref myrot);
2015 }
2016 else
2017 {
2018 // daughter prim, do Geom set
2019 d.GeomSetQuaternion(prim_geom, ref myrot);
2020 }
2021
2022 resetCollisionAccounting();
2023 m_taintrot = _orientation;
2024 }
2025
2026 private void resetCollisionAccounting()
2027 {
2028 m_collisionscore = 0;
2029 m_interpenetrationcount = 0;
2030 m_disabled = false;
2031 }
2032
2033 public void changedisable(float timestep)
2034 {
2035 m_disabled = true;
2036 if (Body != IntPtr.Zero)
2037 {
2038 d.BodyDisable(Body);
2039 Body = IntPtr.Zero;
2040 }
2041
2042 m_taintdisable = false;
2043 }
2044
2045 public void changePhysicsStatus(float timestep)
2046 {
2047 if (m_isphysical == true)
2048 {
2049 if (Body == IntPtr.Zero)
2050 {
2051 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2052 {
2053 changeshape(2f);
2054 }
2055 else
2056 {
2057 enableBody();
2058 }
2059 }
2060 }
2061 else
2062 {
2063 if (Body != IntPtr.Zero)
2064 {
2065 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2066 {
2067 _mesh = null;
2068//Console.WriteLine("changePhysicsStatus for " + m_primName );
2069 changeadd(2f);
2070 }
2071 if (childPrim)
2072 {
2073 if (_parent != null)
2074 {
2075 OdePrim parent = (OdePrim)_parent;
2076 parent.ChildDelink(this);
2077 }
2078 }
2079 else
2080 {
2081 disableBody();
2082 }
2083 }
2084 }
2085
2086 changeSelectedStatus(timestep);
2087
2088 resetCollisionAccounting();
2089 m_taintPhysics = m_isphysical;
2090 }
2091
2092 public void changesize(float timestamp)
2093 {
2094
2095 string oldname = _parent_scene.geom_name_map[prim_geom];
2096
2097 if (_size.X <= 0) _size.X = 0.01f;
2098 if (_size.Y <= 0) _size.Y = 0.01f;
2099 if (_size.Z <= 0) _size.Z = 0.01f;
2100
2101 // Cleanup of old prim geometry
2102 if (_mesh != null)
2103 {
2104 // Cleanup meshing here
2105 }
2106 //kill body to rebuild
2107 if (IsPhysical && Body != IntPtr.Zero)
2108 {
2109 if (childPrim)
2110 {
2111 if (_parent != null)
2112 {
2113 OdePrim parent = (OdePrim)_parent;
2114 parent.ChildDelink(this);
2115 }
2116 }
2117 else
2118 {
2119 disableBody();
2120 }
2121 }
2122 if (d.SpaceQuery(m_targetSpace, prim_geom))
2123 {
2124 _parent_scene.waitForSpaceUnlock(m_targetSpace);
2125 d.SpaceRemove(m_targetSpace, prim_geom);
2126 }
2127 // we don't need to do space calculation because the client sends a position update also.
2128
2129 // Construction of new prim
2130 if (_parent_scene.needsMeshing(_pbs))
2131 {
2132 float meshlod = _parent_scene.meshSculptLOD;
2133
2134 if (IsPhysical)
2135 meshlod = _parent_scene.MeshSculptphysicalLOD;
2136 // Don't need to re-enable body.. it's done in SetMesh
2137
2138 IMesh mesh = null;
2139
2140 if (_parent_scene.needsMeshing(_pbs))
2141 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2142
2143 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2144//Console.WriteLine("changesize 1");
2145 CreateGeom(m_targetSpace, mesh);
2146
2147
2148 }
2149 else
2150 {
2151 _mesh = null;
2152//Console.WriteLine("changesize 2");
2153 CreateGeom(m_targetSpace, _mesh);
2154 }
2155
2156 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2157 d.Quaternion myrot = new d.Quaternion();
2158 myrot.X = _orientation.X;
2159 myrot.Y = _orientation.Y;
2160 myrot.Z = _orientation.Z;
2161 myrot.W = _orientation.W;
2162 d.GeomSetQuaternion(prim_geom, ref myrot);
2163
2164 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2165 if (IsPhysical && Body == IntPtr.Zero && !childPrim)
2166 {
2167 // Re creates body on size.
2168 // EnableBody also does setMass()
2169 enableBody();
2170 d.BodyEnable(Body);
2171 }
2172
2173 _parent_scene.geom_name_map[prim_geom] = oldname;
2174
2175 changeSelectedStatus(timestamp);
2176 if (childPrim)
2177 {
2178 if (_parent is OdePrim)
2179 {
2180 OdePrim parent = (OdePrim)_parent;
2181 parent.ChildSetGeom(this);
2182 }
2183 }
2184 resetCollisionAccounting();
2185 m_taintsize = _size;
2186 }
2187
2188
2189
2190 public void changefloatonwater(float timestep)
2191 {
2192 m_collidesWater = m_taintCollidesWater;
2193
2194 if (prim_geom != IntPtr.Zero)
2195 {
2196 if (m_collidesWater)
2197 {
2198 m_collisionFlags |= CollisionCategories.Water;
2199 }
2200 else
2201 {
2202 m_collisionFlags &= ~CollisionCategories.Water;
2203 }
2204 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2205 }
2206 }
2207
2208 public void changeshape(float timestamp)
2209 {
2210 string oldname = _parent_scene.geom_name_map[prim_geom];
2211
2212 // Cleanup of old prim geometry and Bodies
2213 if (IsPhysical && Body != IntPtr.Zero)
2214 {
2215 if (childPrim)
2216 {
2217 if (_parent != null)
2218 {
2219 OdePrim parent = (OdePrim)_parent;
2220 parent.ChildDelink(this);
2221 }
2222 }
2223 else
2224 {
2225 disableBody();
2226 }
2227 }
2228
2229
2230 // we don't need to do space calculation because the client sends a position update also.
2231 if (_size.X <= 0) _size.X = 0.01f;
2232 if (_size.Y <= 0) _size.Y = 0.01f;
2233 if (_size.Z <= 0) _size.Z = 0.01f;
2234 // Construction of new prim
2235
2236 if (_parent_scene.needsMeshing(_pbs))
2237 {
2238 // Don't need to re-enable body.. it's done in SetMesh
2239 float meshlod = _parent_scene.meshSculptLOD;
2240
2241 if (IsPhysical)
2242 meshlod = _parent_scene.MeshSculptphysicalLOD;
2243
2244 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2245 // createmesh returns null when it doesn't mesh.
2246 CreateGeom(m_targetSpace, mesh);
2247 }
2248 else
2249 {
2250 _mesh = null;
2251//Console.WriteLine("changeshape");
2252 CreateGeom(m_targetSpace, null);
2253 }
2254
2255 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2256 d.Quaternion myrot = new d.Quaternion();
2257 //myrot.W = _orientation.w;
2258 myrot.W = _orientation.W;
2259 myrot.X = _orientation.X;
2260 myrot.Y = _orientation.Y;
2261 myrot.Z = _orientation.Z;
2262 d.GeomSetQuaternion(prim_geom, ref myrot);
2263
2264 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2265 if (IsPhysical && Body == IntPtr.Zero)
2266 {
2267 // Re creates body on size.
2268 // EnableBody also does setMass()
2269 enableBody();
2270 if (Body != IntPtr.Zero)
2271 {
2272 d.BodyEnable(Body);
2273 }
2274 }
2275 _parent_scene.geom_name_map[prim_geom] = oldname;
2276
2277 changeSelectedStatus(timestamp);
2278 if (childPrim)
2279 {
2280 if (_parent is OdePrim)
2281 {
2282 OdePrim parent = (OdePrim)_parent;
2283 parent.ChildSetGeom(this);
2284 }
2285 }
2286 resetCollisionAccounting();
2287 m_taintshape = false;
2288 }
2289
2290 public void changeAddForce(float timestamp)
2291 {
2292 if (!m_isSelected)
2293 {
2294 lock (m_forcelist)
2295 {
2296 //m_log.Info("[PHYSICS]: dequeing forcelist");
2297 if (IsPhysical)
2298 {
2299 Vector3 iforce = Vector3.Zero;
2300 int i = 0;
2301 try
2302 {
2303 for (i = 0; i < m_forcelist.Count; i++)
2304 {
2305
2306 iforce = iforce + (m_forcelist[i] * 100);
2307 }
2308 }
2309 catch (IndexOutOfRangeException)
2310 {
2311 m_forcelist = new List<Vector3>();
2312 m_collisionscore = 0;
2313 m_interpenetrationcount = 0;
2314 m_taintforce = false;
2315 return;
2316 }
2317 catch (ArgumentOutOfRangeException)
2318 {
2319 m_forcelist = new List<Vector3>();
2320 m_collisionscore = 0;
2321 m_interpenetrationcount = 0;
2322 m_taintforce = false;
2323 return;
2324 }
2325 d.BodyEnable(Body);
2326 d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
2327 }
2328 m_forcelist.Clear();
2329 }
2330
2331 m_collisionscore = 0;
2332 m_interpenetrationcount = 0;
2333 }
2334
2335 m_taintforce = false;
2336
2337 }
2338
2339
2340
2341 public void changeSetTorque(float timestamp)
2342 {
2343 if (!m_isSelected)
2344 {
2345 if (IsPhysical && Body != IntPtr.Zero)
2346 {
2347 d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z);
2348 }
2349 }
2350
2351 m_taintTorque = Vector3.Zero;
2352 }
2353
2354 public void changeAddAngularForce(float timestamp)
2355 {
2356 if (!m_isSelected)
2357 {
2358 lock (m_angularforcelist)
2359 {
2360 //m_log.Info("[PHYSICS]: dequeing forcelist");
2361 if (IsPhysical)
2362 {
2363 Vector3 iforce = Vector3.Zero;
2364 for (int i = 0; i < m_angularforcelist.Count; i++)
2365 {
2366 iforce = iforce + (m_angularforcelist[i] * 100);
2367 }
2368 d.BodyEnable(Body);
2369 d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z);
2370
2371 }
2372 m_angularforcelist.Clear();
2373 }
2374
2375 m_collisionscore = 0;
2376 m_interpenetrationcount = 0;
2377 }
2378
2379 m_taintaddangularforce = false;
2380 }
2381
2382 private void changevelocity(float timestep)
2383 {
2384 if (!m_isSelected)
2385 {
2386 Thread.Sleep(20);
2387 if (IsPhysical)
2388 {
2389 if (Body != IntPtr.Zero)
2390 d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
2391 }
2392
2393 //resetCollisionAccounting();
2394 }
2395 m_taintVelocity = Vector3.Zero;
2396 }
2397
2398 public void UpdatePositionAndVelocity()
2399 {
2400 return; // moved to the Move () method
2401 }
2402
2403 public d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj)
2404 {
2405 obj.I.M00 = pMat[0, 0];
2406 obj.I.M01 = pMat[0, 1];
2407 obj.I.M02 = pMat[0, 2];
2408 obj.I.M10 = pMat[1, 0];
2409 obj.I.M11 = pMat[1, 1];
2410 obj.I.M12 = pMat[1, 2];
2411 obj.I.M20 = pMat[2, 0];
2412 obj.I.M21 = pMat[2, 1];
2413 obj.I.M22 = pMat[2, 2];
2414 return obj;
2415 }
2416
2417 public override void SubscribeEvents(int ms)
2418 {
2419 m_eventsubscription = ms;
2420 _parent_scene.addCollisionEventReporting(this);
2421 }
2422
2423 public override void UnSubscribeEvents()
2424 {
2425 _parent_scene.remCollisionEventReporting(this);
2426 m_eventsubscription = 0;
2427 }
2428
2429 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
2430 {
2431 if (CollisionEventsThisFrame == null)
2432 CollisionEventsThisFrame = new CollisionEventUpdate();
2433 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
2434 }
2435
2436 public void SendCollisions()
2437 {
2438 if (CollisionEventsThisFrame == null)
2439 return;
2440
2441 base.SendCollisionUpdate(CollisionEventsThisFrame);
2442
2443 if (CollisionEventsThisFrame.m_objCollisionList.Count == 0)
2444 CollisionEventsThisFrame = null;
2445 else
2446 CollisionEventsThisFrame = new CollisionEventUpdate();
2447 }
2448
2449 public override bool SubscribedEvents()
2450 {
2451 if (m_eventsubscription > 0)
2452 return true;
2453 return false;
2454 }
2455
2456 public static Matrix4 Inverse(Matrix4 pMat)
2457 {
2458 if (determinant3x3(pMat) == 0)
2459 {
2460 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
2461 }
2462
2463
2464
2465 return (Adjoint(pMat) / determinant3x3(pMat));
2466 }
2467
2468 public static Matrix4 Adjoint(Matrix4 pMat)
2469 {
2470 Matrix4 adjointMatrix = new Matrix4();
2471 for (int i=0; i<4; i++)
2472 {
2473 for (int j=0; j<4; j++)
2474 {
2475 Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j)))));
2476 }
2477 }
2478
2479 adjointMatrix = Transpose(adjointMatrix);
2480 return adjointMatrix;
2481 }
2482
2483 public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol)
2484 {
2485 Matrix4 minor = new Matrix4();
2486 int m = 0, n = 0;
2487 for (int i = 0; i < 4; i++)
2488 {
2489 if (i == iRow)
2490 continue;
2491 n = 0;
2492 for (int j = 0; j < 4; j++)
2493 {
2494 if (j == iCol)
2495 continue;
2496 Matrix4SetValue(ref minor, m,n, matrix[i, j]);
2497 n++;
2498 }
2499 m++;
2500 }
2501 return minor;
2502 }
2503
2504 public static Matrix4 Transpose(Matrix4 pMat)
2505 {
2506 Matrix4 transposeMatrix = new Matrix4();
2507 for (int i = 0; i < 4; i++)
2508 for (int j = 0; j < 4; j++)
2509 Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]);
2510 return transposeMatrix;
2511 }
2512
2513 public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val)
2514 {
2515 switch (r)
2516 {
2517 case 0:
2518 switch (c)
2519 {
2520 case 0:
2521 pMat.M11 = val;
2522 break;
2523 case 1:
2524 pMat.M12 = val;
2525 break;
2526 case 2:
2527 pMat.M13 = val;
2528 break;
2529 case 3:
2530 pMat.M14 = val;
2531 break;
2532 }
2533
2534 break;
2535 case 1:
2536 switch (c)
2537 {
2538 case 0:
2539 pMat.M21 = val;
2540 break;
2541 case 1:
2542 pMat.M22 = val;
2543 break;
2544 case 2:
2545 pMat.M23 = val;
2546 break;
2547 case 3:
2548 pMat.M24 = val;
2549 break;
2550 }
2551
2552 break;
2553 case 2:
2554 switch (c)
2555 {
2556 case 0:
2557 pMat.M31 = val;
2558 break;
2559 case 1:
2560 pMat.M32 = val;
2561 break;
2562 case 2:
2563 pMat.M33 = val;
2564 break;
2565 case 3:
2566 pMat.M34 = val;
2567 break;
2568 }
2569
2570 break;
2571 case 3:
2572 switch (c)
2573 {
2574 case 0:
2575 pMat.M41 = val;
2576 break;
2577 case 1:
2578 pMat.M42 = val;
2579 break;
2580 case 2:
2581 pMat.M43 = val;
2582 break;
2583 case 3:
2584 pMat.M44 = val;
2585 break;
2586 }
2587
2588 break;
2589 }
2590 }
2591 private static float determinant3x3(Matrix4 pMat)
2592 {
2593 float det = 0;
2594 float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2];
2595 float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0];
2596 float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1];
2597 float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2];
2598 float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0];
2599 float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1];
2600
2601 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
2602 return det;
2603
2604 }
2605
2606 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
2607 {
2608 dst.c.W = src.c.W;
2609 dst.c.X = src.c.X;
2610 dst.c.Y = src.c.Y;
2611 dst.c.Z = src.c.Z;
2612 dst.mass = src.mass;
2613 dst.I.M00 = src.I.M00;
2614 dst.I.M01 = src.I.M01;
2615 dst.I.M02 = src.I.M02;
2616 dst.I.M10 = src.I.M10;
2617 dst.I.M11 = src.I.M11;
2618 dst.I.M12 = src.I.M12;
2619 dst.I.M20 = src.I.M20;
2620 dst.I.M21 = src.I.M21;
2621 dst.I.M22 = src.I.M22;
2622 }
2623
2624 public override void SetMaterial(int pMaterial)
2625 {
2626 m_material = pMaterial;
2627 }
2628
2629 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
2630 {
2631 switch (pParam)
2632 {
2633 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
2634 if (pValue < 0.01f) pValue = 0.01f;
2635 // m_angularDeflectionEfficiency = pValue;
2636 break;
2637 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
2638 if (pValue < 0.1f) pValue = 0.1f;
2639 // m_angularDeflectionTimescale = pValue;
2640 break;
2641 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
2642 if (pValue < 0.3f) pValue = 0.3f;
2643 m_angularMotorDecayTimescale = pValue;
2644 break;
2645 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
2646 if (pValue < 0.3f) pValue = 0.3f;
2647 m_angularMotorTimescale = pValue;
2648 break;
2649 case Vehicle.BANKING_EFFICIENCY:
2650 if (pValue < 0.01f) pValue = 0.01f;
2651 // m_bankingEfficiency = pValue;
2652 break;
2653 case Vehicle.BANKING_MIX:
2654 if (pValue < 0.01f) pValue = 0.01f;
2655 // m_bankingMix = pValue;
2656 break;
2657 case Vehicle.BANKING_TIMESCALE:
2658 if (pValue < 0.01f) pValue = 0.01f;
2659 // m_bankingTimescale = pValue;
2660 break;
2661 case Vehicle.BUOYANCY:
2662 if (pValue < -1f) pValue = -1f;
2663 if (pValue > 1f) pValue = 1f;
2664 m_VehicleBuoyancy = pValue;
2665 break;
2666// case Vehicle.HOVER_EFFICIENCY:
2667// if (pValue < 0f) pValue = 0f;
2668// if (pValue > 1f) pValue = 1f;
2669// m_VhoverEfficiency = pValue;
2670// break;
2671 case Vehicle.HOVER_HEIGHT:
2672 m_VhoverHeight = pValue;
2673 break;
2674 case Vehicle.HOVER_TIMESCALE:
2675 if (pValue < 0.1f) pValue = 0.1f;
2676 m_VhoverTimescale = pValue;
2677 break;
2678 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
2679 if (pValue < 0.01f) pValue = 0.01f;
2680 // m_linearDeflectionEfficiency = pValue;
2681 break;
2682 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
2683 if (pValue < 0.01f) pValue = 0.01f;
2684 // m_linearDeflectionTimescale = pValue;
2685 break;
2686 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
2687 if (pValue < 0.3f) pValue = 0.3f;
2688 m_linearMotorDecayTimescale = pValue;
2689 break;
2690 case Vehicle.LINEAR_MOTOR_TIMESCALE:
2691 if (pValue < 0.1f) pValue = 0.1f;
2692 m_linearMotorTimescale = pValue;
2693 break;
2694 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
2695 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
2696 if (pValue > 1.0f) pValue = 1.0f;
2697 m_verticalAttractionEfficiency = pValue;
2698 break;
2699 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
2700 if (pValue < 0.1f) pValue = 0.1f;
2701 m_verticalAttractionTimescale = pValue;
2702 break;
2703
2704 // These are vector properties but the engine lets you use a single float value to
2705 // set all of the components to the same value
2706 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2707 if (pValue > 30f) pValue = 30f;
2708 if (pValue < 0.1f) pValue = 0.1f;
2709 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
2710 break;
2711 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2712 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
2713 UpdateAngDecay();
2714 break;
2715 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2716 if (pValue < 0.1f) pValue = 0.1f;
2717 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
2718 break;
2719 case Vehicle.LINEAR_MOTOR_DIRECTION:
2720 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
2721 UpdateLinDecay();
2722 break;
2723 case Vehicle.LINEAR_MOTOR_OFFSET:
2724 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
2725 break;
2726
2727 }
2728
2729 }//end ProcessFloatVehicleParam
2730
2731 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
2732 {
2733 switch (pParam)
2734 {
2735 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2736 if (pValue.X > 30f) pValue.X = 30f;
2737 if (pValue.X < 0.1f) pValue.X = 0.1f;
2738 if (pValue.Y > 30f) pValue.Y = 30f;
2739 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2740 if (pValue.Z > 30f) pValue.Z = 30f;
2741 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2742 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2743 break;
2744 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2745 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
2746 // Limit requested angular speed to 2 rps= 4 pi rads/sec
2747 if(m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
2748 if(m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
2749 if(m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
2750 if(m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
2751 if(m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
2752 if(m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
2753 UpdateAngDecay();
2754 break;
2755 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2756 if (pValue.X < 0.1f) pValue.X = 0.1f;
2757 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2758 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2759 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2760 break;
2761 case Vehicle.LINEAR_MOTOR_DIRECTION:
2762 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting
2763 UpdateLinDecay();
2764 break;
2765 case Vehicle.LINEAR_MOTOR_OFFSET:
2766 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
2767 break;
2768 }
2769
2770 }//end ProcessVectorVehicleParam
2771
2772 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
2773 {
2774 switch (pParam)
2775 {
2776 case Vehicle.REFERENCE_FRAME:
2777 // m_referenceFrame = pValue;
2778 break;
2779 }
2780
2781 }//end ProcessRotationVehicleParam
2782
2783 internal void ProcessVehicleFlags(int pParam, bool remove)
2784 {
2785 if (remove)
2786 {
2787 m_flags &= ~((VehicleFlag)pParam);
2788 }
2789 else
2790 {
2791 m_flags |= (VehicleFlag)pParam;
2792 }
2793 }
2794
2795 internal void ProcessTypeChange(Vehicle pType)
2796 {
2797 // Set Defaults For Type
2798 m_type = pType;
2799 switch (pType)
2800 {
2801 case Vehicle.TYPE_SLED:
2802 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
2803 m_angularFrictionTimescale = new Vector3(30, 30, 30);
2804// m_lLinMotorVel = Vector3.Zero;
2805 m_linearMotorTimescale = 1000;
2806 m_linearMotorDecayTimescale = 120;
2807 m_angularMotorDirection = Vector3.Zero;
2808 m_angularMotorDVel = Vector3.Zero;
2809 m_angularMotorTimescale = 1000;
2810 m_angularMotorDecayTimescale = 120;
2811 m_VhoverHeight = 0;
2812// m_VhoverEfficiency = 1;
2813 m_VhoverTimescale = 10;
2814 m_VehicleBuoyancy = 0;
2815 // m_linearDeflectionEfficiency = 1;
2816 // m_linearDeflectionTimescale = 1;
2817 // m_angularDeflectionEfficiency = 1;
2818 // m_angularDeflectionTimescale = 1000;
2819 // m_bankingEfficiency = 0;
2820 // m_bankingMix = 1;
2821 // m_bankingTimescale = 10;
2822 // m_referenceFrame = Quaternion.Identity;
2823 m_flags &=
2824 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2825 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2826 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2827 break;
2828 case Vehicle.TYPE_CAR:
2829 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
2830 m_angularFrictionTimescale = new Vector3(30, 30, 30); // was 1000, but sl max frict time is 30.
2831// m_lLinMotorVel = Vector3.Zero;
2832 m_linearMotorTimescale = 1;
2833 m_linearMotorDecayTimescale = 60;
2834 m_angularMotorDirection = Vector3.Zero;
2835 m_angularMotorDVel = Vector3.Zero;
2836 m_angularMotorTimescale = 1;
2837 m_angularMotorDecayTimescale = 0.8f;
2838 m_VhoverHeight = 0;
2839// m_VhoverEfficiency = 0;
2840 m_VhoverTimescale = 1000;
2841 m_VehicleBuoyancy = 0;
2842 // // m_linearDeflectionEfficiency = 1;
2843 // // m_linearDeflectionTimescale = 2;
2844 // // m_angularDeflectionEfficiency = 0;
2845 // m_angularDeflectionTimescale = 10;
2846 m_verticalAttractionEfficiency = 1f;
2847 m_verticalAttractionTimescale = 10f;
2848 // m_bankingEfficiency = -0.2f;
2849 // m_bankingMix = 1;
2850 // m_bankingTimescale = 1;
2851 // m_referenceFrame = Quaternion.Identity;
2852 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2853 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY |
2854 VehicleFlag.LIMIT_MOTOR_UP);
2855 break;
2856 case Vehicle.TYPE_BOAT:
2857 m_linearFrictionTimescale = new Vector3(10, 3, 2);
2858 m_angularFrictionTimescale = new Vector3(10,10,10);
2859// m_lLinMotorVel = Vector3.Zero;
2860 m_linearMotorTimescale = 5;
2861 m_linearMotorDecayTimescale = 60;
2862 m_angularMotorDirection = Vector3.Zero;
2863 m_angularMotorDVel = Vector3.Zero;
2864 m_angularMotorTimescale = 4;
2865 m_angularMotorDecayTimescale = 4;
2866 m_VhoverHeight = 0;
2867// m_VhoverEfficiency = 0.5f;
2868 m_VhoverTimescale = 2;
2869 m_VehicleBuoyancy = 1;
2870 // m_linearDeflectionEfficiency = 0.5f;
2871 // m_linearDeflectionTimescale = 3;
2872 // m_angularDeflectionEfficiency = 0.5f;
2873 // m_angularDeflectionTimescale = 5;
2874 m_verticalAttractionEfficiency = 0.5f;
2875 m_verticalAttractionTimescale = 5f;
2876 // m_bankingEfficiency = -0.3f;
2877 // m_bankingMix = 0.8f;
2878 // m_bankingTimescale = 1;
2879 // m_referenceFrame = Quaternion.Identity;
2880 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY |
2881 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2882 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY |
2883 VehicleFlag.LIMIT_MOTOR_UP);
2884 break;
2885 case Vehicle.TYPE_AIRPLANE:
2886 m_linearFrictionTimescale = new Vector3(200, 10, 5);
2887 m_angularFrictionTimescale = new Vector3(20, 20, 20);
2888// m_lLinMotorVel = Vector3.Zero;
2889 m_linearMotorTimescale = 2;
2890 m_linearMotorDecayTimescale = 60;
2891 m_angularMotorDirection = Vector3.Zero;
2892 m_angularMotorDVel = Vector3.Zero;
2893 m_angularMotorTimescale = 4;
2894 m_angularMotorDecayTimescale = 4;
2895 m_VhoverHeight = 0;
2896// m_VhoverEfficiency = 0.5f;
2897 m_VhoverTimescale = 1000;
2898 m_VehicleBuoyancy = 0;
2899 // m_linearDeflectionEfficiency = 0.5f;
2900 // m_linearDeflectionTimescale = 3;
2901 // m_angularDeflectionEfficiency = 1;
2902 // m_angularDeflectionTimescale = 2;
2903 m_verticalAttractionEfficiency = 0.9f;
2904 m_verticalAttractionTimescale = 2f;
2905 // m_bankingEfficiency = 1;
2906 // m_bankingMix = 0.7f;
2907 // m_bankingTimescale = 2;
2908 // m_referenceFrame = Quaternion.Identity;
2909 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2910 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2911 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
2912 break;
2913 case Vehicle.TYPE_BALLOON:
2914 m_linearFrictionTimescale = new Vector3(5, 5, 5);
2915 m_angularFrictionTimescale = new Vector3(10, 10, 10);
2916 m_linearMotorTimescale = 5;
2917 m_linearMotorDecayTimescale = 60;
2918 m_angularMotorDirection = Vector3.Zero;
2919 m_angularMotorDVel = Vector3.Zero;
2920 m_angularMotorTimescale = 6;
2921 m_angularMotorDecayTimescale = 10;
2922 m_VhoverHeight = 5;
2923// m_VhoverEfficiency = 0.8f;
2924 m_VhoverTimescale = 10;
2925 m_VehicleBuoyancy = 1;
2926 // m_linearDeflectionEfficiency = 0;
2927 // m_linearDeflectionTimescale = 5;
2928 // m_angularDeflectionEfficiency = 0;
2929 // m_angularDeflectionTimescale = 5;
2930 m_verticalAttractionEfficiency = 1f;
2931 m_verticalAttractionTimescale = 100f;
2932 // m_bankingEfficiency = 0;
2933 // m_bankingMix = 0.7f;
2934 // m_bankingTimescale = 5;
2935 // m_referenceFrame = Quaternion.Identity;
2936 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2937 VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2938 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2939 break;
2940
2941 }
2942 }//end SetDefaultsForType
2943
2944 internal void Enable(IntPtr pBody, OdeScene pParentScene)
2945 {
2946 if (m_type == Vehicle.TYPE_NONE)
2947 return;
2948
2949 m_body = pBody;
2950 }
2951
2952
2953 internal void Halt()
2954 { // Kill all motions, when non-physical
2955 // m_linearMotorDirection = Vector3.Zero;
2956 m_lLinMotorDVel = Vector3.Zero;
2957 m_lLinObjectVel = Vector3.Zero;
2958 m_wLinObjectVel = Vector3.Zero;
2959 m_angularMotorDirection = Vector3.Zero;
2960 m_lastAngularVelocity = Vector3.Zero;
2961 m_angularMotorDVel = Vector3.Zero;
2962 _acceleration = Vector3.Zero;
2963 }
2964
2965 private void UpdateLinDecay()
2966 {
2967// if (Math.Abs(m_linearMotorDirection.X) > Math.Abs(m_lLinMotorDVel.X)) m_lLinMotorDVel.X = m_linearMotorDirection.X;
2968// if (Math.Abs(m_linearMotorDirection.Y) > Math.Abs(m_lLinMotorDVel.Y)) m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2969// if (Math.Abs(m_linearMotorDirection.Z) > Math.Abs(m_lLinMotorDVel.Z)) m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2970 m_lLinMotorDVel.X = m_linearMotorDirection.X;
2971 m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2972 m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2973 } // else let the motor decay on its own
2974
2975 private void UpdateAngDecay()
2976 {
2977// if (Math.Abs(m_angularMotorDirection.X) > Math.Abs(m_angularMotorDVel.X)) m_angularMotorDVel.X = m_angularMotorDirection.X;
2978// if (Math.Abs(m_angularMotorDirection.Y) > Math.Abs(m_angularMotorDVel.Y)) m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2979// if (Math.Abs(m_angularMotorDirection.Z) > Math.Abs(m_angularMotorDVel.Z)) m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2980 m_angularMotorDVel.X = m_angularMotorDirection.X;
2981 m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2982 m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2983 } // else let the motor decay on its own
2984
2985 public void Move(float timestep)
2986 {
2987 float fx = 0;
2988 float fy = 0;
2989 float fz = 0;
2990 Vector3 linvel; // velocity applied, including any reversal
2991 int outside = 0;
2992
2993 // If geomCrossingFailuresBeforeOutofbounds is set to 0 in OpenSim.ini then phys objects bounce off region borders.
2994 // This is a temp patch until proper region crossing is developed.
2995
2996 int failureLimit = _parent_scene.geomCrossingFailuresBeforeOutofbounds;
2997 int fence = _parent_scene.geomRegionFence;
2998
2999 float border_limit = 0.05f; // original limit
3000 if (fence == 1) border_limit = 0.5f; // bounce point
3001
3002 frcount++; // used to limit debug comment output
3003 if (frcount > 50)
3004 frcount = 0;
3005
3006 if(revcount > 0) revcount--;
3007
3008 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // Only move root prims.
3009 {
3010 // Old public void UpdatePositionAndVelocity(), more accuratley calculated here
3011 bool lastZeroFlag = _zeroFlag; // was it stopped
3012
3013 d.Vector3 vec = d.BodyGetPosition(Body);
3014 Vector3 l_position = Vector3.Zero;
3015 l_position.X = vec.X;
3016 l_position.Y = vec.Y;
3017 l_position.Z = vec.Z;
3018 m_lastposition = _position;
3019 _position = l_position;
3020
3021 d.Quaternion ori = d.BodyGetQuaternion(Body);
3022 // Quaternion l_orientation = Quaternion.Identity;
3023 _orientation.X = ori.X;
3024 _orientation.Y = ori.Y;
3025 _orientation.Z = ori.Z;
3026 _orientation.W = ori.W;
3027 m_lastorientation = _orientation;
3028
3029 d.Vector3 vel = d.BodyGetLinearVel(Body);
3030 m_lastVelocity = _velocity;
3031 _velocity.X = vel.X;
3032 _velocity.Y = vel.Y;
3033 _velocity.Z = vel.Z;
3034 _acceleration = ((_velocity - m_lastVelocity) / timestep);
3035
3036 d.Vector3 torque = d.BodyGetTorque(Body);
3037 _torque = new Vector3(torque.X, torque.Y, torque.Z);
3038
3039 base.RequestPhysicsterseUpdate();
3040
3041//Console.WriteLine("Move {0} at {1}", m_primName, l_position);
3042
3043 // Check if outside region
3044 // In Scene.cs/CrossPrimGroupIntoNewRegion the object is checked for 0.1M from border!
3045 if (l_position.X > ((float)_parent_scene.WorldExtents.X - border_limit))
3046 {
3047 l_position.X = ((float)_parent_scene.WorldExtents.X - border_limit);
3048 outside = 1;
3049 }
3050
3051 if (l_position.X < border_limit)
3052 {
3053 l_position.X = border_limit;
3054 outside = 2;
3055 }
3056 if (l_position.Y > ((float)_parent_scene.WorldExtents.Y - border_limit))
3057 {
3058 l_position.Y = ((float)_parent_scene.WorldExtents.Y - border_limit);
3059 outside = 3;
3060 }
3061
3062 if (l_position.Y < border_limit)
3063 {
3064 l_position.Y = border_limit;
3065 outside = 4;
3066 }
3067
3068 if (outside > 0)
3069 {
3070//Console.WriteLine(" fence = {0}",fence);
3071
3072//Console.WriteLine("Border {0}", l_position);
3073 if (fence == 1) // bounce object off boundary
3074 {
3075 if (revcount == 0)
3076 {
3077 if (outside < 3)
3078 {
3079 _velocity.X = -_velocity.X;
3080 }
3081 else
3082 {
3083 _velocity.Y = -_velocity.Y;
3084 }
3085 if (m_type != Vehicle.TYPE_NONE) Halt();
3086 _position = l_position;
3087 m_taintposition = _position;
3088 m_lastVelocity = _velocity;
3089 _acceleration = Vector3.Zero;
3090 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
3091 d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
3092 base.RequestPhysicsterseUpdate();
3093
3094 revcount = 25; // wait for object to move away from border
3095 }
3096 } // else old crossing mode
3097 else if (m_crossingfailures < failureLimit)
3098 { // keep trying to cross?
3099 _position = l_position;
3100 //_parent_scene.remActivePrim(this);
3101 if (_parent == null) base.RequestPhysicsterseUpdate();
3102 return; // Dont process any other motion?
3103 }
3104 else
3105 { // Too many tries
3106 if (_parent == null) base.RaiseOutOfBounds(l_position);
3107//Console.WriteLine("ROOB 2");
3108
3109 return; // Dont process any other motion?
3110 } // end various methods
3111 } // end outside region horizontally
3112
3113
3114 if (l_position.Z < 0)
3115 {
3116 // This is so prim that get lost underground don't fall forever and suck up
3117 //
3118 // Sim resources and memory.
3119 // Disables the prim's movement physics....
3120 // It's a hack and will generate a console message if it fails.
3121
3122 //IsPhysical = false;
3123 if (_parent == null) base.RaiseOutOfBounds(_position);
3124//Console.WriteLine("ROOB 3");
3125
3126
3127 _acceleration.X = 0; // This stuff may stop client display but it has no
3128 _acceleration.Y = 0; // effect on the object in phys engine!
3129 _acceleration.Z = 0;
3130
3131 _velocity.X = 0;
3132 _velocity.Y = 0;
3133 _velocity.Z = 0;
3134 m_rotationalVelocity.X = 0;
3135 m_rotationalVelocity.Y = 0;
3136 m_rotationalVelocity.Z = 0;
3137
3138 if (_parent == null) base.RequestPhysicsterseUpdate();
3139
3140 m_throttleUpdates = false;
3141 throttleCounter = 0;
3142 _zeroFlag = true;
3143 //outofBounds = true;
3144 } // end neg Z check
3145
3146 // Is it moving?
3147 if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
3148 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
3149 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02)
3150 && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, _orientation)) < 0.0001)) // KF 0.01 is far to large
3151 {
3152 _zeroFlag = true;
3153 m_throttleUpdates = false;
3154 }
3155 else
3156 {
3157 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
3158 _zeroFlag = false;
3159 m_lastUpdateSent = false;
3160 //m_throttleUpdates = false;
3161 }
3162
3163 if (_zeroFlag)
3164 { // Its stopped
3165 _velocity.X = 0.0f;
3166 _velocity.Y = 0.0f;
3167 _velocity.Z = 0.0f;
3168
3169 _acceleration.X = 0;
3170 _acceleration.Y = 0;
3171 _acceleration.Z = 0;
3172
3173 m_rotationalVelocity.X = 0;
3174 m_rotationalVelocity.Y = 0;
3175 m_rotationalVelocity.Z = 0;
3176 if (!m_lastUpdateSent)
3177 {
3178 m_throttleUpdates = false;
3179 throttleCounter = 0;
3180 if (_parent == null)
3181 {
3182 base.RequestPhysicsterseUpdate();
3183 }
3184
3185 m_lastUpdateSent = true;
3186 }
3187 }
3188 else
3189 { // Its moving
3190 if (lastZeroFlag != _zeroFlag)
3191 {
3192 if (_parent == null)
3193 {
3194 base.RequestPhysicsterseUpdate();
3195 }
3196 }
3197 m_lastUpdateSent = false;
3198 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
3199 {
3200 if (_parent == null)
3201 {
3202 base.RequestPhysicsterseUpdate();
3203 }
3204 }
3205 else
3206 {
3207 throttleCounter++;
3208 }
3209 }
3210 m_lastposition = l_position;
3211
3212 /// End UpdatePositionAndVelocity insert
3213
3214
3215 // Rotation lock =====================================
3216 if(m_rotateEnableUpdate)
3217 {
3218 // Snapshot current angles, set up Amotor(s)
3219 m_rotateEnableUpdate = false;
3220 m_rotateEnable = m_rotateEnableRequest;
3221Console.WriteLine("RotEnable {0} = {1}",m_primName, m_rotateEnable);
3222
3223 if (Amotor != IntPtr.Zero)
3224 {
3225 d.JointDestroy(Amotor);
3226 Amotor = IntPtr.Zero;
3227Console.WriteLine("Old Amotor Destroyed");
3228 }
3229
3230 if (!m_rotateEnable.ApproxEquals(Vector3.One, 0.003f))
3231 { // not all are enabled
3232 d.Quaternion r = d.BodyGetQuaternion(Body);
3233 Quaternion locrot = new Quaternion(r.X, r.Y, r.Z, r.W);
3234 // extract the axes vectors
3235 Vector3 vX = new Vector3(1f,0f,0f);
3236 Vector3 vY = new Vector3(0f,1f,0f);
3237 Vector3 vZ = new Vector3(0f,0f,1f);
3238 vX = vX * locrot;
3239 vY = vY * locrot;
3240 vZ = vZ * locrot;
3241 // snapshot the current angle vectors
3242 m_lockX = vX;
3243 m_lockY = vY;
3244 m_lockZ = vZ;
3245 // m_lockRot = locrot;
3246 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3247 d.JointAttach(Amotor, Body, IntPtr.Zero);
3248 d.JointSetAMotorMode(Amotor, 0); // User mode??
3249Console.WriteLine("New Amotor Created for {0}", m_primName);
3250
3251 float axisnum = 3; // how many to lock
3252 axisnum = (axisnum - (m_rotateEnable.X + m_rotateEnable.Y + m_rotateEnable.Z));
3253 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3254Console.WriteLine("AxisNum={0}",(int)axisnum);
3255
3256 int i = 0;
3257
3258 if (m_rotateEnable.X == 0)
3259 {
3260 d.JointSetAMotorAxis(Amotor, i, 0, m_lockX.X, m_lockX.Y, m_lockX.Z);
3261Console.WriteLine("AxisX {0} set to {1}", i, m_lockX);
3262 i++;
3263 }
3264
3265 if (m_rotateEnable.Y == 0)
3266 {
3267 d.JointSetAMotorAxis(Amotor, i, 0, m_lockY.X, m_lockY.Y, m_lockY.Z);
3268Console.WriteLine("AxisY {0} set to {1}", i, m_lockY);
3269 i++;
3270 }
3271
3272 if (m_rotateEnable.Z == 0)
3273 {
3274 d.JointSetAMotorAxis(Amotor, i, 0, m_lockZ.X, m_lockZ.Y, m_lockZ.Z);
3275Console.WriteLine("AxisZ {0} set to {1}", i, m_lockZ);
3276 i++;
3277 }
3278
3279 // These lowstops and high stops are effectively (no wiggle room)
3280 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0f);
3281 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
3282 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0f);
3283 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3284 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3285 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3286 d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 0f);
3287 d.JointSetAMotorParam(Amotor, (int) dParam.Vel3, 0f);
3288 d.JointSetAMotorParam(Amotor, (int) dParam.Vel2, 0f);
3289 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM, 0f);
3290 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM3, 0f);
3291 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM2, 0f);
3292 } // else none are locked
3293 } // end Rotation Update
3294
3295
3296 // VEHICLE processing ==========================================
3297 if (m_type != Vehicle.TYPE_NONE)
3298 {
3299 // get body attitude
3300 d.Quaternion rot = d.BodyGetQuaternion(Body);
3301 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
3302 Quaternion irotq = Quaternion.Inverse(rotq);
3303
3304 // VEHICLE Linear Motion
3305 d.Vector3 velnow = d.BodyGetLinearVel(Body); // this is in world frame
3306 Vector3 vel_now = new Vector3(velnow.X, velnow.Y, velnow.Z);
3307 m_lLinObjectVel = vel_now * irotq;
3308
3309 if (m_linearMotorDecayTimescale < 300.0f) //setting of 300 or more disables decay rate
3310 {
3311 if ( Vector3.Mag(m_lLinMotorDVel) < 1.0f)
3312 {
3313 float decayfactor = m_linearMotorDecayTimescale/timestep;
3314 Vector3 decayAmount = (m_lLinMotorDVel/decayfactor);
3315 m_lLinMotorDVel -= decayAmount;
3316 }
3317 else
3318 {
3319 float decayfactor = 3.0f - (0.57f * (float)Math.Log((double)(m_linearMotorDecayTimescale)));
3320 Vector3 decel = Vector3.Normalize(m_lLinMotorDVel) * decayfactor * timestep;
3321 m_lLinMotorDVel -= decel;
3322 }
3323 if (m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3324 {
3325 m_lLinMotorDVel = Vector3.Zero;
3326 }
3327
3328 /* else
3329 {
3330 if (Math.Abs(m_lLinMotorDVel.X) < Math.Abs(m_lLinObjectVel.X)) m_lLinObjectVel.X = m_lLinMotorDVel.X;
3331 if (Math.Abs(m_lLinMotorDVel.Y) < Math.Abs(m_lLinObjectVel.Y)) m_lLinObjectVel.Y = m_lLinMotorDVel.Y;
3332 if (Math.Abs(m_lLinMotorDVel.Z) < Math.Abs(m_lLinObjectVel.Z)) m_lLinObjectVel.Z = m_lLinMotorDVel.Z;
3333 } */
3334 } // end linear motor decay
3335
3336 if ( (! m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! m_lLinObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3337 {
3338 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3339 if (m_linearMotorTimescale < 300.0f)
3340 {
3341 Vector3 attack_error = m_lLinMotorDVel - m_lLinObjectVel;
3342 float linfactor = m_linearMotorTimescale/timestep;
3343 Vector3 attackAmount = (attack_error/linfactor) * 1.3f;
3344 m_lLinObjectVel += attackAmount;
3345 }
3346 if (m_linearFrictionTimescale.X < 300.0f)
3347 {
3348 float fricfactor = m_linearFrictionTimescale.X / timestep;
3349 float fricX = m_lLinObjectVel.X / fricfactor;
3350 m_lLinObjectVel.X -= fricX;
3351 }
3352 if (m_linearFrictionTimescale.Y < 300.0f)
3353 {
3354 float fricfactor = m_linearFrictionTimescale.Y / timestep;
3355 float fricY = m_lLinObjectVel.Y / fricfactor;
3356 m_lLinObjectVel.Y -= fricY;
3357 }
3358 if (m_linearFrictionTimescale.Z < 300.0f)
3359 {
3360 float fricfactor = m_linearFrictionTimescale.Z / timestep;
3361 float fricZ = m_lLinObjectVel.Z / fricfactor;
3362 m_lLinObjectVel.Z -= fricZ;
3363 }
3364 }
3365 m_wLinObjectVel = m_lLinObjectVel * rotq;
3366
3367 // Gravity and Buoyancy
3368 Vector3 grav = Vector3.Zero;
3369 if(m_VehicleBuoyancy < 1.0f)
3370 {
3371 // There is some gravity, make a gravity force vector
3372 // that is applied after object velocity.
3373 d.Mass objMass;
3374 d.BodyGetMass(Body, out objMass);
3375 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
3376 grav.Z = _parent_scene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); // Applied later as a force
3377 } // else its 1.0, no gravity.
3378
3379 // Hovering
3380 if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
3381 {
3382 // We should hover, get the target height
3383 d.Vector3 pos = d.BodyGetPosition(Body);
3384 if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY)
3385 {
3386 m_VhoverTargetHeight = _parent_scene.GetWaterLevel() + m_VhoverHeight;
3387 }
3388 else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY)
3389 {
3390 m_VhoverTargetHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
3391 }
3392 else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT)
3393 {
3394 m_VhoverTargetHeight = m_VhoverHeight;
3395 }
3396
3397 if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY)
3398 {
3399 // If body is aready heigher, use its height as target height
3400 if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
3401 }
3402
3403// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
3404// m_VhoverTimescale = 0f; // time to acheive height
3405// timestep is time since last frame,in secs
3406 float herr0 = pos.Z - m_VhoverTargetHeight;
3407 // Replace Vertical speed with correction figure if significant
3408 if(Math.Abs(herr0) > 0.01f )
3409 {
3410 //? d.Mass objMass;
3411 //? d.BodyGetMass(Body, out objMass);
3412 m_wLinObjectVel.Z = - ( (herr0 * timestep * 50.0f) / m_VhoverTimescale);
3413 //KF: m_VhoverEfficiency is not yet implemented
3414 }
3415 else
3416 {
3417 m_wLinObjectVel.Z = 0f;
3418 }
3419 }
3420 else
3421 { // not hovering
3422 if (m_wLinObjectVel.Z == 0f)
3423 { // Gravity rules
3424 m_wLinObjectVel.Z = vel_now.Z;
3425 } // else the motor has it
3426 }
3427 linvel = m_wLinObjectVel;
3428
3429 // Vehicle Linear Motion done =======================================
3430 // Apply velocity
3431 d.BodySetLinearVel(Body, linvel.X, linvel.Y, linvel.Z);
3432 // apply gravity force
3433 d.BodyAddForce(Body, grav.X, grav.Y, grav.Z);
3434//if(frcount == 0) Console.WriteLine("Grav {0}", grav);
3435 // end MoveLinear()
3436
3437
3438 // MoveAngular
3439 /*
3440 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
3441
3442 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
3443 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
3444 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
3445
3446 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
3447 private Vector3 m_angObjectVel = Vector3.Zero; // what was last applied to body
3448 */
3449//if(frcount == 0) Console.WriteLine("MoveAngular ");
3450
3451 d.Vector3 angularObjectVel = d.BodyGetAngularVel(Body);
3452 Vector3 angObjectVel = new Vector3(angularObjectVel.X, angularObjectVel.Y, angularObjectVel.Z);
3453 angObjectVel = angObjectVel * irotq; // ============ Converts to LOCAL rotation
3454
3455//if(frcount == 0) Console.WriteLine("V0 = {0}", angObjectVel);
3456
3457 // Decay Angular Motor 1. In SL this also depends on attack rate! decay ~= 23/Attack.
3458 float atk_decayfactor = 23.0f / (m_angularMotorTimescale * timestep);
3459 m_angularMotorDVel -= m_angularMotorDVel / atk_decayfactor;
3460 // Decay Angular Motor 2.
3461 if (m_angularMotorDecayTimescale < 300.0f)
3462 {
3463 if ( Vector3.Mag(m_angularMotorDVel) < 1.0f)
3464 {
3465 float decayfactor = (m_angularMotorDecayTimescale)/timestep;
3466 Vector3 decayAmount = (m_angularMotorDVel/decayfactor);
3467 m_angularMotorDVel -= decayAmount;
3468 }
3469 else
3470 {
3471 Vector3 decel = Vector3.Normalize(m_angularMotorDVel) * timestep / m_angularMotorDecayTimescale;
3472 m_angularMotorDVel -= decel;
3473 }
3474
3475 if (m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3476 {
3477 m_angularMotorDVel = Vector3.Zero;
3478 }
3479 else
3480 {
3481 if (Math.Abs(m_angularMotorDVel.X) < Math.Abs(angObjectVel.X)) angObjectVel.X = m_angularMotorDVel.X;
3482 if (Math.Abs(m_angularMotorDVel.Y) < Math.Abs(angObjectVel.Y)) angObjectVel.Y = m_angularMotorDVel.Y;
3483 if (Math.Abs(m_angularMotorDVel.Z) < Math.Abs(angObjectVel.Z)) angObjectVel.Z = m_angularMotorDVel.Z;
3484 }
3485 } // end decay angular motor
3486//if(frcount == 0) Console.WriteLine("MotorDvel {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3487
3488//if(frcount == 0) Console.WriteLine("VA = {0}", angObjectVel);
3489
3490 if ( (! m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! angObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3491 { // if motor or object have motion
3492 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3493
3494 if (m_angularMotorTimescale < 300.0f)
3495 {
3496 Vector3 attack_error = m_angularMotorDVel - angObjectVel;
3497 float angfactor = m_angularMotorTimescale/timestep;
3498 Vector3 attackAmount = (attack_error/angfactor);
3499 angObjectVel += attackAmount;
3500//if(frcount == 0) Console.WriteLine("Accel {0} Attk {1}",FrAaccel, attackAmount);
3501//if(frcount == 0) Console.WriteLine("V2+= {0}", angObjectVel);
3502 }
3503
3504 angObjectVel.X -= angObjectVel.X / (m_angularFrictionTimescale.X * 0.7f / timestep);
3505 angObjectVel.Y -= angObjectVel.Y / (m_angularFrictionTimescale.Y * 0.7f / timestep);
3506 angObjectVel.Z -= angObjectVel.Z / (m_angularFrictionTimescale.Z * 0.7f / timestep);
3507 } // else no signif. motion
3508
3509//if(frcount == 0) Console.WriteLine("Dmotor {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3510 // Bank section tba
3511 // Deflection section tba
3512//if(frcount == 0) Console.WriteLine("V3 = {0}", angObjectVel);
3513
3514
3515 /* // Rotation Axis Disables:
3516 if (!m_angularEnable.ApproxEquals(Vector3.One, 0.003f))
3517 {
3518 if (m_angularEnable.X == 0)
3519 angObjectVel.X = 0f;
3520 if (m_angularEnable.Y == 0)
3521 angObjectVel.Y = 0f;
3522 if (m_angularEnable.Z == 0)
3523 angObjectVel.Z = 0f;
3524 }
3525 */
3526 angObjectVel = angObjectVel * rotq; // ================ Converts to WORLD rotation
3527
3528 // Vertical attractor section
3529 Vector3 vertattr = Vector3.Zero;
3530
3531 if(m_verticalAttractionTimescale < 300)
3532 {
3533 float VAservo = 1.0f / (m_verticalAttractionTimescale * timestep);
3534 // make a vector pointing up
3535 Vector3 verterr = Vector3.Zero;
3536 verterr.Z = 1.0f;
3537 // rotate it to Body Angle
3538 verterr = verterr * rotq;
3539 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
3540 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
3541 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
3542
3543 if (verterr.Z < 0.0f)
3544 { // Deflection from vertical exceeds 90-degrees. This method will ensure stable return to
3545 // vertical, BUT for some reason a z-rotation is imparted to the object. TBI.
3546//Console.WriteLine("InvertFlip");
3547 verterr.X = 2.0f - verterr.X;
3548 verterr.Y = 2.0f - verterr.Y;
3549 }
3550 verterr *= 0.5f;
3551 // verterror is 0 (no error) to +/- 1 (max error at 180-deg tilt)
3552 Vector3 xyav = angObjectVel;
3553 xyav.Z = 0.0f;
3554 if ((!xyav.ApproxEquals(Vector3.Zero, 0.001f)) || (verterr.Z < 0.49f))
3555 {
3556 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
3557 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
3558 vertattr.X = verterr.Y;
3559 vertattr.Y = - verterr.X;
3560 vertattr.Z = 0f;
3561//if(frcount == 0) Console.WriteLine("VAerr=" + verterr);
3562
3563 // scaling appears better usingsquare-law
3564 float damped = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
3565 float bounce = 1.0f - damped;
3566 // 0 = crit damp, 1 = bouncy
3567 float oavz = angObjectVel.Z; // retain z velocity
3568 // time-scaled correction, which sums, therefore is bouncy:
3569 angObjectVel = (angObjectVel + (vertattr * VAservo * 0.0333f)) * bounce;
3570 // damped, good @ < 90:
3571 angObjectVel = angObjectVel + (vertattr * VAservo * 0.0667f * damped);
3572 angObjectVel.Z = oavz;
3573//if(frcount == 0) Console.WriteLine("VA+");
3574//Console.WriteLine("VAttr {0} OAvel {1}", vertattr, angObjectVel);
3575 }
3576 else
3577 {
3578 // else error is very small
3579 angObjectVel.X = 0f;
3580 angObjectVel.Y = 0f;
3581//if(frcount == 0) Console.WriteLine("VA0");
3582 }
3583 } // else vertical attractor is off
3584//if(frcount == 0) Console.WriteLine("V1 = {0}", angObjectVel);
3585
3586
3587 m_lastAngularVelocity = angObjectVel;
3588 // apply Angular Velocity to body
3589 d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z);
3590//if(frcount == 0) Console.WriteLine("V4 = {0}", m_lastAngularVelocity);
3591
3592 } // end VEHICLES
3593 else
3594 {
3595 // Dyamics (NON-'VEHICLES') are dealt with here ================================================================
3596
3597 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009
3598
3599 /// Dynamics Buoyancy
3600 //KF: m_buoyancy is set by llSetBuoyancy() and is for non-vehicle.
3601 // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up
3602 // NB Prims in ODE are no subject to global gravity
3603 // This should only affect gravity operations
3604
3605 float m_mass = CalculateMass();
3606 // calculate z-force due togravity on object.
3607 fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; // force = acceleration * mass
3608
3609 if ((m_usePID) && (m_PIDTau > 0.0f)) // Dynamics llMoveToTarget.
3610 {
3611 fz = 0; // llMoveToTarget ignores gravity.
3612 // it also ignores mass of object, and any physical resting on it.
3613 // Vector3 m_PIDTarget is where we are going
3614 // float m_PIDTau is time to get there
3615 fx = 0;
3616 fy = 0;
3617 d.Vector3 pos = d.BodyGetPosition(Body);
3618 Vector3 error = new Vector3(
3619 (m_PIDTarget.X - pos.X),
3620 (m_PIDTarget.Y - pos.Y),
3621 (m_PIDTarget.Z - pos.Z));
3622 if (error.ApproxEquals(Vector3.Zero,0.01f))
3623 { // Very close, Jump there and quit move
3624 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3625 _target_velocity = Vector3.Zero;
3626 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3627 }
3628 else
3629 {
3630 float scale = 50.0f * timestep / m_PIDTau;
3631 if ((error.ApproxEquals(Vector3.Zero,0.5f)) && (_target_velocity != Vector3.Zero))
3632 {
3633 // Nearby, quit update of velocity
3634 }
3635 else
3636 { // Far, calc damped velocity
3637 _target_velocity = error * scale;
3638 }
3639 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3640 }
3641 } // end PID MoveToTarget
3642
3643 /* Original OS implementation: Does not work correctly as another phys object resting on THIS object purturbs its position.
3644 This is incorrect behavior. llMoveToTarget must move the Body no matter what phys object is resting on it.
3645
3646 //if (!d.BodyIsEnabled(Body))
3647 //d.BodySetForce(Body, 0f, 0f, 0f);
3648
3649 // no lock; for now it's only called from within Simulate()
3650
3651 // If the PID Controller isn't active then we set our force
3652 // calculating base velocity to the current position
3653
3654 if ((m_PIDTau < 1) && (m_PIDTau != 0))
3655 {
3656 //PID_G = PID_G / m_PIDTau;
3657 m_PIDTau = 1;
3658 }
3659
3660 if ((PID_G - m_PIDTau) <= 0)
3661 {
3662 PID_G = m_PIDTau + 1;
3663 }
3664 //PidStatus = true;
3665
3666 // PhysicsVector vec = new PhysicsVector();
3667// d.Vector3 vel = d.BodyGetLinearVel(Body);
3668
3669 d.Vector3 pos = d.BodyGetPosition(Body);
3670 _target_velocity =
3671 new Vector3(
3672 (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep),
3673 (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep),
3674 (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep)
3675 );
3676
3677if(frcount == 0) Console.WriteLine("PID {0} b={1} fz={2} vel={3}", m_primName, m_buoyancy, fz, _target_velocity);
3678 // if velocity is zero, use position control; otherwise, velocity control
3679
3680 if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f))
3681 {
3682 // keep track of where we stopped. No more slippin' & slidin'
3683
3684 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3685 // react to the physics scene by moving it's position.
3686 // Avatar to Avatar collisions
3687 // Prim to avatar collisions
3688
3689 //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
3690 //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2);
3691 //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
3692 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3693 d.BodySetLinearVel(Body, 0, 0, 0);
3694 d.BodyAddForce(Body, 0, 0, fz);
3695 // return;
3696 }
3697 else
3698 {
3699 _zeroFlag = false;
3700
3701 // We're flying and colliding with something
3702 fx = ((_target_velocity.X) - vel.X) * (PID_D);
3703 fy = ((_target_velocity.Y) - vel.Y) * (PID_D);
3704
3705 // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
3706
3707 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3708 }
3709 } // end if (m_usePID)
3710 End of old PID system */
3711
3712
3713 /// Dynamics Hover ===================================================================================
3714 // Hover PID Controller can only run if the PIDcontroller is not in use.
3715 if (m_useHoverPID && !m_usePID)
3716 {
3717//Console.WriteLine("Hover " + m_primName);
3718
3719 // If we're using the PID controller, then we have no gravity
3720 fz = (-1 * _parent_scene.gravityz) * m_mass;
3721
3722 // no lock; for now it's only called from within Simulate()
3723
3724 // If the PID Controller isn't active then we set our force
3725 // calculating base velocity to the current position
3726
3727 if ((m_PIDTau < 1))
3728 {
3729 PID_G = PID_G / m_PIDTau;
3730 }
3731
3732 if ((PID_G - m_PIDTau) <= 0)
3733 {
3734 PID_G = m_PIDTau + 1;
3735 }
3736
3737
3738 // Where are we, and where are we headed?
3739 d.Vector3 pos = d.BodyGetPosition(Body);
3740// d.Vector3 vel = d.BodyGetLinearVel(Body);
3741
3742
3743 // Non-Vehicles have a limited set of Hover options.
3744 // determine what our target height really is based on HoverType
3745 switch (m_PIDHoverType)
3746 {
3747 case PIDHoverType.Ground:
3748 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3749 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3750 break;
3751 case PIDHoverType.GroundAndWater:
3752 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3753 m_waterHeight = _parent_scene.GetWaterLevel();
3754 if (m_groundHeight > m_waterHeight)
3755 {
3756 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3757 }
3758 else
3759 {
3760 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
3761 }
3762 break;
3763
3764 } // end switch (m_PIDHoverType)
3765
3766
3767 _target_velocity =
3768 new Vector3(0.0f, 0.0f,
3769 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
3770 );
3771
3772 // if velocity is zero, use position control; otherwise, velocity control
3773
3774 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
3775 {
3776 // keep track of where we stopped. No more slippin' & slidin'
3777
3778 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3779 // react to the physics scene by moving it's position.
3780 // Avatar to Avatar collisions
3781 // Prim to avatar collisions
3782 d.Vector3 dlinvel = vel;
3783
3784 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
3785 d.BodySetLinearVel(Body, dlinvel.X, dlinvel.Y, dlinvel.Z);
3786 d.BodyAddForce(Body, 0, 0, fz);
3787 //KF this prevents furthur motions return;
3788 }
3789 else
3790 {
3791 _zeroFlag = false;
3792
3793 // We're flying and colliding with something
3794 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3795 }
3796 } // end m_useHoverPID && !m_usePID
3797
3798 /// Dynamics RotLookAt =================================================================================
3799 if (m_useAPID)
3800 {
3801 // RotLookAt, apparently overrides all other rotation sources. Inputs:
3802 // Quaternion m_APIDTarget
3803 // float m_APIDStrength // From SL experiments, this is the time to get there
3804 // float m_APIDDamping // From SL experiments, this is damping, 1.0 = damped, 0.1 = wobbly
3805 // Also in SL the mass of the object has no effect on time to get there.
3806 // Factors:
3807 // get present body rotation
3808 float limit = 1.0f;
3809 float scaler = 50f; // adjusts damping time
3810 float RLAservo = 0f;
3811
3812 d.Quaternion rot = d.BodyGetQuaternion(Body);
3813 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
3814 Quaternion rot_diff = Quaternion.Inverse(rotq) * m_APIDTarget;
3815 float diff_angle;
3816 Vector3 diff_axis;
3817 rot_diff.GetAxisAngle(out diff_axis, out diff_angle);
3818 diff_axis.Normalize();
3819 if(diff_angle > 0.01f) // diff_angle is always +ve
3820 {
3821// PhysicsVector rotforce = new PhysicsVector(diff_axis.X, diff_axis.Y, diff_axis.Z);
3822 Vector3 rotforce = new Vector3(diff_axis.X, diff_axis.Y, diff_axis.Z);
3823 rotforce = rotforce * rotq;
3824 if(diff_angle > limit) diff_angle = limit; // cap the rotate rate
3825// RLAservo = timestep / m_APIDStrength * m_mass * scaler;
3826 // rotforce = rotforce * RLAservo * diff_angle ;
3827 // d.BodyAddRelTorque(Body, rotforce.X, rotforce.Y, rotforce.Z);
3828 RLAservo = timestep / m_APIDStrength * scaler;
3829 rotforce = rotforce * RLAservo * diff_angle ;
3830 /*
3831 if (m_angularEnable.X == 0)
3832 rotforce.X = 0;
3833 if (m_angularEnable.Y == 0)
3834 rotforce.Y = 0;
3835 if (m_angularEnable.Z == 0)
3836 rotforce.Z = 0;
3837 */
3838 d.BodySetAngularVel (Body, rotforce.X, rotforce.Y, rotforce.Z);
3839//Console.WriteLine("axis= " + diff_axis + " angle= " + diff_angle + "servo= " + RLAservo);
3840 }
3841//if(frcount == 0) Console.WriteLine("mass= " + m_mass + " servo= " + RLAservo + " angle= " + diff_angle);
3842 } // end m_useAPID
3843
3844 /// Dynamics Apply Forces ===================================================================================
3845 fx *= m_mass;
3846 fy *= m_mass;
3847 //fz *= m_mass;
3848
3849 fx += m_force.X;
3850 fy += m_force.Y;
3851 fz += m_force.Z;
3852
3853 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
3854 if (fx != 0 || fy != 0 || fz != 0)
3855 {
3856 //m_taintdisable = true;
3857 //base.RaiseOutOfBounds(Position);
3858 //d.BodySetLinearVel(Body, fx, fy, 0f);
3859 if (!d.BodyIsEnabled(Body))
3860 {
3861 // A physical body at rest on a surface will auto-disable after a while,
3862 // this appears to re-enable it incase the surface it is upon vanishes,
3863 // and the body should fall again.
3864 d.BodySetLinearVel(Body, 0f, 0f, 0f);
3865 d.BodySetForce(Body, 0, 0, 0);
3866 enableBodySoft();
3867 }
3868
3869 // 35x10 = 350n times the mass per second applied maximum.
3870 float nmax = 35f * m_mass;
3871 float nmin = -35f * m_mass;
3872
3873
3874 if (fx > nmax)
3875 fx = nmax;
3876 if (fx < nmin)
3877 fx = nmin;
3878 if (fy > nmax)
3879 fy = nmax;
3880 if (fy < nmin)
3881 fy = nmin;
3882 d.BodyAddForce(Body, fx, fy, fz);
3883//Console.WriteLine("AddForce " + fx + "," + fy + "," + fz);
3884 } // end apply forces
3885 } // end Dynamics
3886
3887/* obsolete?
3888 else
3889 { // is not physical, or is not a body or is selected
3890 // from old UpdatePositionAndVelocity, ... Not a body.. so Make sure the client isn't interpolating
3891 _velocity.X = 0;
3892 _velocity.Y = 0;
3893 _velocity.Z = 0;
3894
3895 _acceleration.X = 0;
3896 _acceleration.Y = 0;
3897 _acceleration.Z = 0;
3898
3899 m_rotationalVelocity.X = 0;
3900 m_rotationalVelocity.Y = 0;
3901 m_rotationalVelocity.Z = 0;
3902 _zeroFlag = true;
3903 return;
3904 }
3905 */
3906 } // end root prims
3907
3908 } // end Move()
3909 } // end class
3910}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs
new file mode 100644
index 0000000..7314107
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs
@@ -0,0 +1,375 @@
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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using OpenMetaverse;
34using OpenSim.Region.Physics.Manager;
35using Ode.NET;
36using log4net;
37
38namespace OpenSim.Region.Physics.OdePlugin
39{
40 /// <summary>
41 /// Processes raycast requests as ODE is in a state to be able to do them.
42 /// This ensures that it's thread safe and there will be no conflicts.
43 /// Requests get returned by a different thread then they were requested by.
44 /// </summary>
45 public class ODERayCastRequestManager
46 {
47 /// <summary>
48 /// Pending Raycast Requests
49 /// </summary>
50 protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>();
51
52 /// <summary>
53 /// Scene that created this object.
54 /// </summary>
55 private OdeScene m_scene;
56
57 /// <summary>
58 /// ODE contact array to be filled by the collision testing
59 /// </summary>
60 d.ContactGeom[] contacts = new d.ContactGeom[5];
61
62 /// <summary>
63 /// ODE near callback delegate
64 /// </summary>
65 private d.NearCallback nearCallback;
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private List<ContactResult> m_contactResults = new List<ContactResult>();
68
69
70 public ODERayCastRequestManager(OdeScene pScene)
71 {
72 m_scene = pScene;
73 nearCallback = near;
74
75 }
76
77 /// <summary>
78 /// Queues a raycast
79 /// </summary>
80 /// <param name="position">Origin of Ray</param>
81 /// <param name="direction">Ray normal</param>
82 /// <param name="length">Ray length</param>
83 /// <param name="retMethod">Return method to send the results</param>
84 public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
85 {
86 lock (m_PendingRequests)
87 {
88 ODERayCastRequest req = new ODERayCastRequest();
89 req.callbackMethod = retMethod;
90 req.length = length;
91 req.Normal = direction;
92 req.Origin = position;
93
94 m_PendingRequests.Add(req);
95 }
96 }
97
98 /// <summary>
99 /// Process all queued raycast requests
100 /// </summary>
101 /// <returns>Time in MS the raycasts took to process.</returns>
102 public int ProcessQueuedRequests()
103 {
104 int time = System.Environment.TickCount;
105 lock (m_PendingRequests)
106 {
107 if (m_PendingRequests.Count > 0)
108 {
109 ODERayCastRequest[] reqs = m_PendingRequests.ToArray();
110 for (int i = 0; i < reqs.Length; i++)
111 {
112 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
113 RayCast(reqs[i]); // if there isn't anyone to send results
114 }
115 /*
116 foreach (ODERayCastRequest req in m_PendingRequests)
117 {
118 if (req.callbackMethod != null) // quick optimization here, don't raycast
119 RayCast(req); // if there isn't anyone to send results to
120
121 }
122 */
123 m_PendingRequests.Clear();
124 }
125 }
126
127 lock (m_contactResults)
128 m_contactResults.Clear();
129
130 return System.Environment.TickCount - time;
131 }
132
133 /// <summary>
134 /// Method that actually initiates the raycast
135 /// </summary>
136 /// <param name="req"></param>
137 private void RayCast(ODERayCastRequest req)
138 {
139 // Create the ray
140 IntPtr ray = d.CreateRay(m_scene.space, req.length);
141 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
142
143 // Collide test
144 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
145
146 // Remove Ray
147 d.GeomDestroy(ray);
148
149
150 // Define default results
151 bool hitYN = false;
152 uint hitConsumerID = 0;
153 float distance = 999999999999f;
154 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
155 Vector3 snormal = Vector3.Zero;
156
157 // Find closest contact and object.
158 lock (m_contactResults)
159 {
160 foreach (ContactResult cResult in m_contactResults)
161 {
162 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
163 {
164 closestcontact = cResult.Pos;
165 hitConsumerID = cResult.ConsumerID;
166 distance = cResult.Depth;
167 hitYN = true;
168 snormal = cResult.Normal;
169 }
170 }
171
172 m_contactResults.Clear();
173 }
174
175 // Return results
176 if (req.callbackMethod != null)
177 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal);
178 }
179
180 // This is the standard Near. Uses space AABBs to speed up detection.
181 private void near(IntPtr space, IntPtr g1, IntPtr g2)
182 {
183
184 //Don't test against heightfield Geom, or you'll be sorry!
185
186 /*
187 terminate called after throwing an instance of 'std::bad_alloc'
188 what(): std::bad_alloc
189 Stacktrace:
190
191 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
192 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
193 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
194 at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
195 fffff>
196 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
197 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
198 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
199 0x00114>
200 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
201 at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
202 at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
203 at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
204 at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
205 at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>
206
207 Native stacktrace:
208
209 mono [0x80d2a42]
210 [0xb7f5840c]
211 /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
212 /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
213 /usr/lib/libstdc++.so.6 [0xb45fa865]
214 /usr/lib/libstdc++.so.6 [0xb45fa8a2]
215 /usr/lib/libstdc++.so.6 [0xb45fa9da]
216 /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
217 /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
218 libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
219 libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
220 libode.so(dCollide+0x102) [0xb46571b2]
221 [0x95cfdec9]
222 [0x8ea07fe1]
223 [0xab260146]
224 libode.so [0xb465a5c4]
225 libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
226 libode.so(dSpaceCollide2+0x177) [0xb465ac67]
227 [0x95cf978e]
228 [0x8ea07945]
229 [0x95cf2bbc]
230 [0xab2787e7]
231 [0xab419fb3]
232 [0xab416657]
233 [0xab415bda]
234 [0xb609b08e]
235 mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
236 mono [0x81a2f0f]
237 mono [0x81d28b6]
238 mono [0x81ea2c6]
239 /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
240 /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
241 */
242
243 // Exclude heightfield geom
244
245 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
246 return;
247 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
248 return;
249
250 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
251 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
252 {
253 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
254 return;
255
256 // Separating static prim geometry spaces.
257 // We'll be calling near recursivly if one
258 // of them is a space to find all of the
259 // contact points in the space
260 try
261 {
262 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
263 }
264 catch (AccessViolationException)
265 {
266 m_log.Warn("[PHYSICS]: Unable to collide test a space");
267 return;
268 }
269 //Colliding a space or a geom with a space or a geom. so drill down
270
271 //Collide all geoms in each space..
272 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
273 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
274 return;
275 }
276
277 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
278 return;
279
280 int count = 0;
281 try
282 {
283
284 if (g1 == g2)
285 return; // Can't collide with yourself
286
287 lock (contacts)
288 {
289 count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
290 }
291 }
292 catch (SEHException)
293 {
294 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
295 }
296 catch (Exception e)
297 {
298 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
299 return;
300 }
301
302 PhysicsActor p1 = null;
303 PhysicsActor p2 = null;
304
305 if (g1 != IntPtr.Zero)
306 m_scene.actor_name_map.TryGetValue(g1, out p1);
307
308 if (g2 != IntPtr.Zero)
309 m_scene.actor_name_map.TryGetValue(g1, out p2);
310
311 // Loop over contacts, build results.
312 for (int i = 0; i < count; i++)
313 {
314 if (p1 != null) {
315 if (p1 is OdePrim)
316 {
317 ContactResult collisionresult = new ContactResult();
318
319 collisionresult.ConsumerID = ((OdePrim)p1).m_localID;
320 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
321 collisionresult.Depth = contacts[i].depth;
322 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
323 contacts[i].normal.Z);
324 lock (m_contactResults)
325 m_contactResults.Add(collisionresult);
326 }
327 }
328
329 if (p2 != null)
330 {
331 if (p2 is OdePrim)
332 {
333 ContactResult collisionresult = new ContactResult();
334
335 collisionresult.ConsumerID = ((OdePrim)p2).m_localID;
336 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
337 collisionresult.Depth = contacts[i].depth;
338 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
339 contacts[i].normal.Z);
340
341 lock (m_contactResults)
342 m_contactResults.Add(collisionresult);
343 }
344 }
345
346
347 }
348
349 }
350
351 /// <summary>
352 /// Dereference the creator scene so that it can be garbage collected if needed.
353 /// </summary>
354 internal void Dispose()
355 {
356 m_scene = null;
357 }
358 }
359
360 public struct ODERayCastRequest
361 {
362 public Vector3 Origin;
363 public Vector3 Normal;
364 public float length;
365 public RaycastCallback callbackMethod;
366 }
367
368 public struct ContactResult
369 {
370 public Vector3 Pos;
371 public float Depth;
372 public uint ConsumerID;
373 public Vector3 Normal;
374 }
375}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs
new file mode 100644
index 0000000..b4a3c48
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs
@@ -0,0 +1,48 @@
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
28using System;
29using OpenMetaverse;
30using Ode.NET;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.OdePlugin;
34
35namespace OpenSim.Region.Physics.OdePlugin
36{
37 class OdePhysicsJoint : PhysicsJoint
38 {
39 public override bool IsInPhysicsEngine
40 {
41 get
42 {
43 return (jointID != IntPtr.Zero);
44 }
45 }
46 public IntPtr jointID;
47 }
48}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
new file mode 100644
index 0000000..ab084fd
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
@@ -0,0 +1,3859 @@
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//#define USE_DRAWSTUFF
29
30using System;
31using System.Collections.Generic;
32using System.Reflection;
33using System.Runtime.InteropServices;
34using System.Threading;
35using System.IO;
36using System.Diagnostics;
37using log4net;
38using Nini.Config;
39using Ode.NET;
40#if USE_DRAWSTUFF
41using Drawstuff.NET;
42#endif
43using OpenSim.Framework;
44using OpenSim.Region.Physics.Manager;
45using OpenMetaverse;
46
47//using OpenSim.Region.Physics.OdePlugin.Meshing;
48
49namespace OpenSim.Region.Physics.OdePlugin
50{
51 /// <summary>
52 /// ODE plugin
53 /// </summary>
54 public class OdePlugin : IPhysicsPlugin
55 {
56 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
57
58 private CollisionLocker ode;
59 private OdeScene _mScene;
60
61 public OdePlugin()
62 {
63 ode = new CollisionLocker();
64 }
65
66 public bool Init()
67 {
68 return true;
69 }
70
71 public PhysicsScene GetScene(String sceneIdentifier)
72 {
73 if (_mScene == null)
74 {
75 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
76 // http://opensimulator.org/mantis/view.php?id=2750).
77 d.InitODE();
78
79 _mScene = new OdeScene(ode, sceneIdentifier);
80 }
81 return (_mScene);
82 }
83
84 public string GetName()
85 {
86 return ("ChODE");
87 }
88
89 public void Dispose()
90 {
91 }
92 }
93
94 public enum StatusIndicators : int
95 {
96 Generic = 0,
97 Start = 1,
98 End = 2
99 }
100
101 public struct sCollisionData
102 {
103 public uint ColliderLocalId;
104 public uint CollidedWithLocalId;
105 public int NumberOfCollisions;
106 public int CollisionType;
107 public int StatusIndicator;
108 public int lastframe;
109 }
110
111 [Flags]
112 public enum CollisionCategories : int
113 {
114 Disabled = 0,
115 Geom = 0x00000001,
116 Body = 0x00000002,
117 Space = 0x00000004,
118 Character = 0x00000008,
119 Land = 0x00000010,
120 Water = 0x00000020,
121 Wind = 0x00000040,
122 Sensor = 0x00000080,
123 Selected = 0x00000100
124 }
125
126 /// <summary>
127 /// Material type for a primitive
128 /// </summary>
129 public enum Material : int
130 {
131 /// <summary></summary>
132 Stone = 0,
133 /// <summary></summary>
134 Metal = 1,
135 /// <summary></summary>
136 Glass = 2,
137 /// <summary></summary>
138 Wood = 3,
139 /// <summary></summary>
140 Flesh = 4,
141 /// <summary></summary>
142 Plastic = 5,
143 /// <summary></summary>
144 Rubber = 6
145
146 }
147
148 public sealed class OdeScene : PhysicsScene
149 {
150 private readonly ILog m_log;
151 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
152
153 CollisionLocker ode;
154
155 private Random fluidRandomizer = new Random(Environment.TickCount);
156
157 private const uint m_regionWidth = Constants.RegionSize;
158 private const uint m_regionHeight = Constants.RegionSize;
159
160 private float ODE_STEPSIZE = 0.020f;
161 private float metersInSpace = 29.9f;
162 private float m_timeDilation = 1.0f;
163
164 public float gravityx = 0f;
165 public float gravityy = 0f;
166 public float gravityz = -9.8f;
167
168 private float contactsurfacelayer = 0.001f;
169
170 private int worldHashspaceLow = -4;
171 private int worldHashspaceHigh = 128;
172
173 private int smallHashspaceLow = -4;
174 private int smallHashspaceHigh = 66;
175
176 private float waterlevel = 0f;
177 private int framecount = 0;
178 //private int m_returncollisions = 10;
179
180 private readonly IntPtr contactgroup;
181
182 internal IntPtr LandGeom;
183 internal IntPtr WaterGeom;
184
185 private float nmTerrainContactFriction = 255.0f;
186 private float nmTerrainContactBounce = 0.1f;
187 private float nmTerrainContactERP = 0.1025f;
188
189 private float mTerrainContactFriction = 75f;
190 private float mTerrainContactBounce = 0.1f;
191 private float mTerrainContactERP = 0.05025f;
192
193 private float nmAvatarObjectContactFriction = 250f;
194 private float nmAvatarObjectContactBounce = 0.1f;
195
196 private float mAvatarObjectContactFriction = 75f;
197 private float mAvatarObjectContactBounce = 0.1f;
198
199 private float avPIDD = 3200f;
200 private float avPIDP = 1400f;
201 private float avCapRadius = 0.37f;
202 private float avStandupTensor = 2000000f;
203 private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode
204 public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } }
205 private float avDensity = 80f;
206 private float avHeightFudgeFactor = 0.52f;
207 private float avMovementDivisorWalk = 1.3f;
208 private float avMovementDivisorRun = 0.8f;
209 private float minimumGroundFlightOffset = 3f;
210 public float maximumMassObject = 10000.01f;
211
212 public bool meshSculptedPrim = true;
213 public bool forceSimplePrimMeshing = false;
214
215 public float meshSculptLOD = 32;
216 public float MeshSculptphysicalLOD = 16;
217
218 public float geomDefaultDensity = 10.000006836f;
219
220 public int geomContactPointsStartthrottle = 3;
221 public int geomUpdatesPerThrottledUpdate = 15;
222
223 public float bodyPIDD = 35f;
224 public float bodyPIDG = 25;
225
226 public int geomCrossingFailuresBeforeOutofbounds = 5;
227 public int geomRegionFence = 0;
228
229 public float bodyMotorJointMaxforceTensor = 2;
230
231 public int bodyFramesAutoDisable = 20;
232
233 private DateTime m_lastframe = DateTime.UtcNow;
234
235 private float[] _watermap;
236 private bool m_filterCollisions = true;
237
238 private d.NearCallback nearCallback;
239 public d.TriCallback triCallback;
240 public d.TriArrayCallback triArrayCallback;
241 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
242 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
243 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
244 private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>();
245 private readonly Object _taintedPrimLock = new Object();
246 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
247 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
248 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
249 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
250 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
251 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
252 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
253 private bool m_NINJA_physics_joints_enabled = false;
254 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
255 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
256 private d.ContactGeom[] contacts;
257 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
258 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
259 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
260 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
261 private Object externalJointRequestsLock = new Object();
262 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
263 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
264 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
265 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
266
267 private d.Contact contact;
268 private d.Contact TerrainContact;
269 private d.Contact AvatarMovementprimContact;
270 private d.Contact AvatarMovementTerrainContact;
271 private d.Contact WaterContact;
272 private d.Contact[,] m_materialContacts;
273
274//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
275//Ckrinke private int m_randomizeWater = 200;
276 private int m_physicsiterations = 10;
277 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
278 private readonly PhysicsActor PANull = new NullPhysicsActor();
279 private float step_time = 0.0f;
280//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
281//Ckrinke private int ms = 0;
282 public IntPtr world;
283 //private bool returncollisions = false;
284 // private uint obj1LocalID = 0;
285 private uint obj2LocalID = 0;
286 //private int ctype = 0;
287 private OdeCharacter cc1;
288 private OdePrim cp1;
289 private OdeCharacter cc2;
290 private OdePrim cp2;
291 //private int cStartStop = 0;
292 //private string cDictKey = "";
293
294 public IntPtr space;
295
296 //private IntPtr tmpSpace;
297 // split static geometry collision handling into spaces of 30 meters
298 public IntPtr[,] staticPrimspace;
299
300 public Object OdeLock;
301
302 public IMesher mesher;
303
304 private IConfigSource m_config;
305
306 public bool physics_logging = false;
307 public int physics_logging_interval = 0;
308 public bool physics_logging_append_existing_logfile = false;
309
310 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
311 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
312
313 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
314 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
315 // TODO: unused: private uint heightmapWidthSamples;
316 // TODO: unused: private uint heightmapHeightSamples;
317
318 private volatile int m_global_contactcount = 0;
319
320 private Vector3 m_worldOffset = Vector3.Zero;
321 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
322 private PhysicsScene m_parentScene = null;
323
324 private ODERayCastRequestManager m_rayCastManager;
325
326 /// <summary>
327 /// Initiailizes the scene
328 /// Sets many properties that ODE requires to be stable
329 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
330 /// </summary>
331 public OdeScene(CollisionLocker dode, string sceneIdentifier)
332 {
333 m_log
334 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
335
336 OdeLock = new Object();
337 ode = dode;
338 nearCallback = near;
339 triCallback = TriCallback;
340 triArrayCallback = TriArrayCallback;
341 m_rayCastManager = new ODERayCastRequestManager(this);
342 lock (OdeLock)
343 {
344 // Create the world and the first space
345 world = d.WorldCreate();
346 space = d.HashSpaceCreate(IntPtr.Zero);
347
348
349 contactgroup = d.JointGroupCreate(0);
350 //contactgroup
351
352 d.WorldSetAutoDisableFlag(world, false);
353 #if USE_DRAWSTUFF
354
355 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
356 viewthread.Start();
357 #endif
358 }
359
360
361 _watermap = new float[258 * 258];
362
363 // Zero out the prim spaces array (we split our space into smaller spaces so
364 // we can hit test less.
365 }
366
367#if USE_DRAWSTUFF
368 public void startvisualization(object o)
369 {
370 ds.Functions fn;
371 fn.version = ds.VERSION;
372 fn.start = new ds.CallbackFunction(start);
373 fn.step = new ds.CallbackFunction(step);
374 fn.command = new ds.CallbackFunction(command);
375 fn.stop = null;
376 fn.path_to_textures = "./textures";
377 string[] args = new string[0];
378 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
379 }
380#endif
381
382 // Initialize the mesh plugin
383 public override void Initialise(IMesher meshmerizer, IConfigSource config)
384 {
385 mesher = meshmerizer;
386 m_config = config;
387 // Defaults
388
389 if (Environment.OSVersion.Platform == PlatformID.Unix)
390 {
391 avPIDD = 3200.0f;
392 avPIDP = 1400.0f;
393 avStandupTensor = 2000000f;
394 }
395 else
396 {
397 avPIDD = 2200.0f;
398 avPIDP = 900.0f;
399 avStandupTensor = 550000f;
400 }
401
402 int contactsPerCollision = 80;
403
404 if (m_config != null)
405 {
406 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
407 if (physicsconfig != null)
408 {
409 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
410 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
411 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
412
413 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
414 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
415
416 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
417 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
418 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
419
420 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
421
422 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
423 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
424 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
425
426 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
427 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
428 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
429
430 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
431 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
432
433 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
434 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
435
436 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
437 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
438
439 avDensity = physicsconfig.GetFloat("av_density", 80f);
440 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
441 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
442 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
443 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
444 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
445
446 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
447
448 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
449 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
450 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
451 geomRegionFence = physicsconfig.GetInt("region_border_fence", 0);
452
453 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
454 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
455
456 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
457 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
458
459 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
460 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
461 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
462 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
463 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
464
465 if (Environment.OSVersion.Platform == PlatformID.Unix)
466 {
467 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
468 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
469 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
470 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
471 }
472 else
473 {
474 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
475 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
476 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
477 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
478 }
479
480 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
481 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
482 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
483
484 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
485 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
486 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
487 }
488 }
489
490 contacts = new d.ContactGeom[contactsPerCollision];
491
492 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
493
494 // Centeral contact friction and bounce
495 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
496 // an avatar falls through in Z but not in X or Y when walking on a prim.
497 contact.surface.mode |= d.ContactFlags.SoftERP;
498 contact.surface.mu = nmAvatarObjectContactFriction;
499 contact.surface.bounce = nmAvatarObjectContactBounce;
500 contact.surface.soft_cfm = 0.010f;
501 contact.surface.soft_erp = 0.010f;
502
503 // Terrain contact friction and Bounce
504 // This is the *non* moving version. Use this when an avatar
505 // isn't moving to keep it in place better
506 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
507 TerrainContact.surface.mu = nmTerrainContactFriction;
508 TerrainContact.surface.bounce = nmTerrainContactBounce;
509 TerrainContact.surface.soft_erp = nmTerrainContactERP;
510
511 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
512 WaterContact.surface.mu = 0f; // No friction
513 WaterContact.surface.bounce = 0.0f; // No bounce
514 WaterContact.surface.soft_cfm = 0.010f;
515 WaterContact.surface.soft_erp = 0.010f;
516
517 // Prim contact friction and bounce
518 // THis is the *non* moving version of friction and bounce
519 // Use this when an avatar comes in contact with a prim
520 // and is moving
521 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
522 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
523
524 // Terrain contact friction bounce and various error correcting calculations
525 // Use this when an avatar is in contact with the terrain and moving.
526 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
527 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
528 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
529 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
530
531
532 /*
533 <summary></summary>
534 Stone = 0,
535 /// <summary></summary>
536 Metal = 1,
537 /// <summary></summary>
538 Glass = 2,
539 /// <summary></summary>
540 Wood = 3,
541 /// <summary></summary>
542 Flesh = 4,
543 /// <summary></summary>
544 Plastic = 5,
545 /// <summary></summary>
546 Rubber = 6
547 */
548
549 m_materialContacts = new d.Contact[7,2];
550
551 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
552 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
553 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
554 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
555 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
556 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
557
558 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
559 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
560 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
561 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
562 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
563 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
564
565 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
566 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
567 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
568 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
569 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
570 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
571
572 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
573 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
574 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
575 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
576 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
577 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
578
579 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
580 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
581 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
582 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
583 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
584 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
585
586 /*
587 private float nmAvatarObjectContactFriction = 250f;
588 private float nmAvatarObjectContactBounce = 0.1f;
589
590 private float mAvatarObjectContactFriction = 75f;
591 private float mAvatarObjectContactBounce = 0.1f;
592 */
593 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
594 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
595 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
596 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
597 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
598 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
599
600 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
601 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
602 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
603 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
604 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
605 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
606
607 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
608 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
609 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
610 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
611 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
612 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
613
614 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
615 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
616 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
617 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
618 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
619 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
620
621 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
622 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
623 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
624 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
625 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
626 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
627
628 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
629 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
630 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
631 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
632 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
633 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
634
635 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
636 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
637 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
638 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
639 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
640 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
641
642 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
643 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
644 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
645 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
646 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
647 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
648
649 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
650 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
651 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
652 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
653 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
654 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
655
656 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
657
658 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
659
660 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
661 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
662
663 d.WorldSetLinearDamping(world, 256f);
664 d.WorldSetAngularDamping(world, 256f);
665 d.WorldSetAngularDampingThreshold(world, 256f);
666 d.WorldSetLinearDampingThreshold(world, 256f);
667 d.WorldSetMaxAngularSpeed(world, 256f);
668
669 // Set how many steps we go without running collision testing
670 // This is in addition to the step size.
671 // Essentially Steps * m_physicsiterations
672 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
673 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
674
675
676
677 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
678 {
679 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
680 {
681 staticPrimspace[i, j] = IntPtr.Zero;
682 }
683 }
684 }
685
686 internal void waitForSpaceUnlock(IntPtr space)
687 {
688 //if (space != IntPtr.Zero)
689 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
690 }
691
692 /// <summary>
693 /// Debug space message for printing the space that a prim/avatar is in.
694 /// </summary>
695 /// <param name="pos"></param>
696 /// <returns>Returns which split up space the given position is in.</returns>
697 public string whichspaceamIin(Vector3 pos)
698 {
699 return calculateSpaceForGeom(pos).ToString();
700 }
701
702 #region Collision Detection
703
704 /// <summary>
705 /// This is our near callback. A geometry is near a body
706 /// </summary>
707 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
708 /// <param name="g1">a geometry or space</param>
709 /// <param name="g2">another geometry or space</param>
710 private void near(IntPtr space, IntPtr g1, IntPtr g2)
711 {
712 // no lock here! It's invoked from within Simulate(), which is thread-locked
713
714 // Test if we're colliding a geom with a space.
715 // If so we have to drill down into the space recursively
716
717 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
718 {
719 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
720 return;
721
722 // Separating static prim geometry spaces.
723 // We'll be calling near recursivly if one
724 // of them is a space to find all of the
725 // contact points in the space
726 try
727 {
728 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
729 }
730 catch (AccessViolationException)
731 {
732 m_log.Warn("[PHYSICS]: Unable to collide test a space");
733 return;
734 }
735 //Colliding a space or a geom with a space or a geom. so drill down
736
737 //Collide all geoms in each space..
738 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
739 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
740 return;
741 }
742
743 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
744 return;
745
746 IntPtr b1 = d.GeomGetBody(g1);
747 IntPtr b2 = d.GeomGetBody(g2);
748
749 // d.GeomClassID id = d.GeomGetClass(g1);
750
751 String name1 = null;
752 String name2 = null;
753
754 if (!geom_name_map.TryGetValue(g1, out name1))
755 {
756 name1 = "null";
757 }
758 if (!geom_name_map.TryGetValue(g2, out name2))
759 {
760 name2 = "null";
761 }
762
763 //if (id == d.GeomClassId.TriMeshClass)
764 //{
765 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
766 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
767 //}
768
769 // Figure out how many contact points we have
770 int count = 0;
771 try
772 {
773 // Colliding Geom To Geom
774 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
775
776 if (g1 == g2)
777 return; // Can't collide with yourself
778
779 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
780 return;
781
782 lock (contacts)
783 {
784 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
785 if (count > contacts.Length)
786 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
787 }
788 }
789 catch (SEHException)
790 {
791 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
792 ode.drelease(world);
793 base.TriggerPhysicsBasedRestart();
794 }
795 catch (Exception e)
796 {
797 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
798 return;
799 }
800
801 PhysicsActor p1;
802 PhysicsActor p2;
803
804 if (!actor_name_map.TryGetValue(g1, out p1))
805 {
806 p1 = PANull;
807 }
808
809 if (!actor_name_map.TryGetValue(g2, out p2))
810 {
811 p2 = PANull;
812 }
813
814 ContactPoint maxDepthContact = new ContactPoint();
815 if (p1.CollisionScore + count >= float.MaxValue)
816 p1.CollisionScore = 0;
817 p1.CollisionScore += count;
818
819 if (p2.CollisionScore + count >= float.MaxValue)
820 p2.CollisionScore = 0;
821 p2.CollisionScore += count;
822
823 for (int i = 0; i < count; i++)
824 {
825 d.ContactGeom curContact = contacts[i];
826
827 if (curContact.depth > maxDepthContact.PenetrationDepth)
828 {
829 maxDepthContact = new ContactPoint(
830 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
831 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
832 curContact.depth
833 );
834 }
835
836 //m_log.Warn("[CCOUNT]: " + count);
837 IntPtr joint;
838 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
839 // allows us to have different settings
840
841 // We only need to test p2 for 'jump crouch purposes'
842 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
843 {
844 // Testing if the collision is at the feet of the avatar
845
846 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
847 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
848 p2.IsColliding = true;
849 }
850 else
851 {
852 p2.IsColliding = true;
853 }
854
855 //if ((framecount % m_returncollisions) == 0)
856
857 switch (p1.PhysicsActorType)
858 {
859 case (int)ActorTypes.Agent:
860 p2.CollidingObj = true;
861 break;
862 case (int)ActorTypes.Prim:
863 if (p2.Velocity.LengthSquared() > 0.0f)
864 p2.CollidingObj = true;
865 break;
866 case (int)ActorTypes.Unknown:
867 p2.CollidingGround = true;
868 break;
869 default:
870 p2.CollidingGround = true;
871 break;
872 }
873
874 // we don't want prim or avatar to explode
875
876 #region InterPenetration Handling - Unintended physics explosions
877# region disabled code1
878
879 if (curContact.depth >= 0.08f)
880 {
881 //This is disabled at the moment only because it needs more tweaking
882 //It will eventually be uncommented
883 /*
884 if (contact.depth >= 1.00f)
885 {
886 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
887 }
888
889 //If you interpenetrate a prim with an agent
890 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
891 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
892 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
893 p2.PhysicsActorType == (int) ActorTypes.Prim))
894 {
895
896 //contact.depth = contact.depth * 4.15f;
897 /*
898 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
899 {
900 p2.CollidingObj = true;
901 contact.depth = 0.003f;
902 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
903 OdeCharacter character = (OdeCharacter) p2;
904 character.SetPidStatus(true);
905 contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2));
906
907 }
908 else
909 {
910
911 //contact.depth = 0.0000000f;
912 }
913 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
914 {
915
916 p1.CollidingObj = true;
917 contact.depth = 0.003f;
918 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
919 contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2));
920 OdeCharacter character = (OdeCharacter)p1;
921 character.SetPidStatus(true);
922 }
923 else
924 {
925
926 //contact.depth = 0.0000000f;
927 }
928
929
930
931 }
932*/
933 // If you interpenetrate a prim with another prim
934 /*
935 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
936 {
937 #region disabledcode2
938 //OdePrim op1 = (OdePrim)p1;
939 //OdePrim op2 = (OdePrim)p2;
940 //op1.m_collisionscore++;
941 //op2.m_collisionscore++;
942
943 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
944 //{
945 //op1.m_taintdisable = true;
946 //AddPhysicsActorTaint(p1);
947 //op2.m_taintdisable = true;
948 //AddPhysicsActorTaint(p2);
949 //}
950
951 //if (contact.depth >= 0.25f)
952 //{
953 // Don't collide, one or both prim will expld.
954
955 //op1.m_interpenetrationcount++;
956 //op2.m_interpenetrationcount++;
957 //interpenetrations_before_disable = 200;
958 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
959 //{
960 //op1.m_taintdisable = true;
961 //AddPhysicsActorTaint(p1);
962 //}
963 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
964 //{
965 // op2.m_taintdisable = true;
966 //AddPhysicsActorTaint(p2);
967 //}
968
969 //contact.depth = contact.depth / 8f;
970 //contact.normal = new d.Vector3(0, 0, 1);
971 //}
972 //if (op1.m_disabled || op2.m_disabled)
973 //{
974 //Manually disabled objects stay disabled
975 //contact.depth = 0f;
976 //}
977 #endregion
978 }
979 */
980#endregion
981 if (curContact.depth >= 1.00f)
982 {
983 //m_log.Info("[P]: " + contact.depth.ToString());
984 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
985 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
986 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
987 p2.PhysicsActorType == (int) ActorTypes.Unknown))
988 {
989 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
990 {
991 if (p2 is OdeCharacter)
992 {
993 OdeCharacter character = (OdeCharacter) p2;
994
995 //p2.CollidingObj = true;
996 curContact.depth = 0.00000003f;
997 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
998 curContact.pos =
999 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1000 curContact.pos.Y + (p1.Size.Y/2),
1001 curContact.pos.Z + (p1.Size.Z/2));
1002 character.SetPidStatus(true);
1003 }
1004 }
1005
1006
1007 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1008 {
1009 if (p1 is OdeCharacter)
1010 {
1011 OdeCharacter character = (OdeCharacter) p1;
1012
1013 //p2.CollidingObj = true;
1014 curContact.depth = 0.00000003f;
1015 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1016 curContact.pos =
1017 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1018 curContact.pos.Y + (p1.Size.Y/2),
1019 curContact.pos.Z + (p1.Size.Z/2));
1020 character.SetPidStatus(true);
1021 }
1022 }
1023 }
1024 }
1025 }
1026
1027 #endregion
1028
1029 // Logic for collision handling
1030 // Note, that if *all* contacts are skipped (VolumeDetect)
1031 // The prim still detects (and forwards) collision events but
1032 // appears to be phantom for the world
1033 Boolean skipThisContact = false;
1034
1035 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1036 skipThisContact = true; // No collision on volume detect prims
1037
1038 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1039 skipThisContact = true; // No collision on volume detect prims
1040
1041 if (!skipThisContact && curContact.depth < 0f)
1042 skipThisContact = true;
1043
1044 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1045 skipThisContact = true;
1046
1047 const int maxContactsbeforedeath = 4000;
1048 joint = IntPtr.Zero;
1049
1050 if (!skipThisContact)
1051 {
1052 // If we're colliding against terrain
1053 if (name1 == "Terrain" || name2 == "Terrain")
1054 {
1055 // If we're moving
1056 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1057 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1058 {
1059 // Use the movement terrain contact
1060 AvatarMovementTerrainContact.geom = curContact;
1061 _perloopContact.Add(curContact);
1062 if (m_global_contactcount < maxContactsbeforedeath)
1063 {
1064 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1065 m_global_contactcount++;
1066 }
1067 }
1068 else
1069 {
1070 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1071 {
1072 // Use the non moving terrain contact
1073 TerrainContact.geom = curContact;
1074 _perloopContact.Add(curContact);
1075 if (m_global_contactcount < maxContactsbeforedeath)
1076 {
1077 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1078 m_global_contactcount++;
1079 }
1080 }
1081 else
1082 {
1083 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1084 {
1085 // prim prim contact
1086 // int pj294950 = 0;
1087 int movintYN = 0;
1088 int material = (int) Material.Wood;
1089 // prim terrain contact
1090 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1091 {
1092 movintYN = 1;
1093 }
1094
1095 if (p2 is OdePrim)
1096 material = ((OdePrim)p2).m_material;
1097
1098 //m_log.DebugFormat("Material: {0}", material);
1099 m_materialContacts[material, movintYN].geom = curContact;
1100 _perloopContact.Add(curContact);
1101
1102 if (m_global_contactcount < maxContactsbeforedeath)
1103 {
1104 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1105 m_global_contactcount++;
1106
1107 }
1108
1109 }
1110 else
1111 {
1112
1113 int movintYN = 0;
1114 // prim terrain contact
1115 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1116 {
1117 movintYN = 1;
1118 }
1119
1120 int material = (int)Material.Wood;
1121
1122 if (p2 is OdePrim)
1123 material = ((OdePrim)p2).m_material;
1124 //m_log.DebugFormat("Material: {0}", material);
1125 m_materialContacts[material, movintYN].geom = curContact;
1126 _perloopContact.Add(curContact);
1127
1128 if (m_global_contactcount < maxContactsbeforedeath)
1129 {
1130 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1131 m_global_contactcount++;
1132
1133 }
1134 }
1135 }
1136 }
1137 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1138 //{
1139 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1140 //}
1141 }
1142 else if (name1 == "Water" || name2 == "Water")
1143 {
1144 /*
1145 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1146 {
1147 }
1148 else
1149 {
1150 }
1151 */
1152 //WaterContact.surface.soft_cfm = 0.0000f;
1153 //WaterContact.surface.soft_erp = 0.00000f;
1154 if (curContact.depth > 0.1f)
1155 {
1156 curContact.depth *= 52;
1157 //contact.normal = new d.Vector3(0, 0, 1);
1158 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1159 }
1160 WaterContact.geom = curContact;
1161 _perloopContact.Add(curContact);
1162 if (m_global_contactcount < maxContactsbeforedeath)
1163 {
1164 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1165 m_global_contactcount++;
1166 }
1167 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1168 }
1169 else
1170 {
1171 // we're colliding with prim or avatar
1172 // check if we're moving
1173 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1174 {
1175 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1176 {
1177 // Use the Movement prim contact
1178 AvatarMovementprimContact.geom = curContact;
1179 _perloopContact.Add(curContact);
1180 if (m_global_contactcount < maxContactsbeforedeath)
1181 {
1182 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1183 m_global_contactcount++;
1184 }
1185 }
1186 else
1187 {
1188 // Use the non movement contact
1189 contact.geom = curContact;
1190 _perloopContact.Add(curContact);
1191
1192 if (m_global_contactcount < maxContactsbeforedeath)
1193 {
1194 joint = d.JointCreateContact(world, contactgroup, ref contact);
1195 m_global_contactcount++;
1196 }
1197 }
1198 }
1199 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1200 {
1201 //p1.PhysicsActorType
1202 int material = (int)Material.Wood;
1203
1204 if (p2 is OdePrim)
1205 material = ((OdePrim)p2).m_material;
1206
1207 //m_log.DebugFormat("Material: {0}", material);
1208 m_materialContacts[material, 0].geom = curContact;
1209 _perloopContact.Add(curContact);
1210
1211 if (m_global_contactcount < maxContactsbeforedeath)
1212 {
1213 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1214 m_global_contactcount++;
1215
1216 }
1217 }
1218 }
1219
1220 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1221 {
1222 d.JointAttach(joint, b1, b2);
1223 m_global_contactcount++;
1224 }
1225
1226 }
1227 collision_accounting_events(p1, p2, maxDepthContact);
1228 if (count > geomContactPointsStartthrottle)
1229 {
1230 // If there are more then 3 contact points, it's likely
1231 // that we've got a pile of objects, so ...
1232 // We don't want to send out hundreds of terse updates over and over again
1233 // so lets throttle them and send them again after it's somewhat sorted out.
1234 p2.ThrottleUpdates = true;
1235 }
1236 //m_log.Debug(count.ToString());
1237 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1238 }
1239 }
1240
1241 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1242 {
1243 bool result = false;
1244 //return result;
1245 if (!m_filterCollisions)
1246 return false;
1247
1248 ActorTypes at = (ActorTypes)atype;
1249 lock (_perloopContact)
1250 {
1251 foreach (d.ContactGeom contact in _perloopContact)
1252 {
1253 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1254 //{
1255 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1256 if (at == ActorTypes.Agent)
1257 {
1258 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1259 {
1260
1261 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1262 {
1263 //contactGeom.depth *= .00005f;
1264 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1265 // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1266 result = true;
1267 break;
1268 }
1269 else
1270 {
1271 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1272 }
1273 }
1274 else
1275 {
1276 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1277 //int i = 0;
1278 }
1279 }
1280 else if (at == ActorTypes.Prim)
1281 {
1282 //d.AABB aabb1 = new d.AABB();
1283 //d.AABB aabb2 = new d.AABB();
1284
1285 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1286 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1287 //aabb1.
1288 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1289 {
1290 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1291 {
1292 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1293 {
1294 result = true;
1295 break;
1296 }
1297 }
1298 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1299 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1300 }
1301
1302 }
1303
1304 //}
1305
1306 }
1307 }
1308 return result;
1309 }
1310
1311 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1312 {
1313 // obj1LocalID = 0;
1314 //returncollisions = false;
1315 obj2LocalID = 0;
1316 //ctype = 0;
1317 //cStartStop = 0;
1318 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1319 return;
1320
1321 switch ((ActorTypes)p2.PhysicsActorType)
1322 {
1323 case ActorTypes.Agent:
1324 cc2 = (OdeCharacter)p2;
1325
1326 // obj1LocalID = cc2.m_localID;
1327 switch ((ActorTypes)p1.PhysicsActorType)
1328 {
1329 case ActorTypes.Agent:
1330 cc1 = (OdeCharacter)p1;
1331 obj2LocalID = cc1.m_localID;
1332 cc1.AddCollisionEvent(cc2.m_localID, contact);
1333 //ctype = (int)CollisionCategories.Character;
1334
1335 //if (cc1.CollidingObj)
1336 //cStartStop = (int)StatusIndicators.Generic;
1337 //else
1338 //cStartStop = (int)StatusIndicators.Start;
1339
1340 //returncollisions = true;
1341 break;
1342 case ActorTypes.Prim:
1343 if (p1 is OdePrim)
1344 {
1345 cp1 = (OdePrim) p1;
1346 obj2LocalID = cp1.m_localID;
1347 cp1.AddCollisionEvent(cc2.m_localID, contact);
1348 }
1349 //ctype = (int)CollisionCategories.Geom;
1350
1351 //if (cp1.CollidingObj)
1352 //cStartStop = (int)StatusIndicators.Generic;
1353 //else
1354 //cStartStop = (int)StatusIndicators.Start;
1355
1356 //returncollisions = true;
1357 break;
1358
1359 case ActorTypes.Ground:
1360 case ActorTypes.Unknown:
1361 obj2LocalID = 0;
1362 //ctype = (int)CollisionCategories.Land;
1363 //returncollisions = true;
1364 break;
1365 }
1366
1367 cc2.AddCollisionEvent(obj2LocalID, contact);
1368 break;
1369 case ActorTypes.Prim:
1370
1371 if (p2 is OdePrim)
1372 {
1373 cp2 = (OdePrim) p2;
1374
1375 // obj1LocalID = cp2.m_localID;
1376 switch ((ActorTypes) p1.PhysicsActorType)
1377 {
1378 case ActorTypes.Agent:
1379 if (p1 is OdeCharacter)
1380 {
1381 cc1 = (OdeCharacter) p1;
1382 obj2LocalID = cc1.m_localID;
1383 cc1.AddCollisionEvent(cp2.m_localID, contact);
1384 //ctype = (int)CollisionCategories.Character;
1385
1386 //if (cc1.CollidingObj)
1387 //cStartStop = (int)StatusIndicators.Generic;
1388 //else
1389 //cStartStop = (int)StatusIndicators.Start;
1390 //returncollisions = true;
1391 }
1392 break;
1393 case ActorTypes.Prim:
1394
1395 if (p1 is OdePrim)
1396 {
1397 cp1 = (OdePrim) p1;
1398 obj2LocalID = cp1.m_localID;
1399 cp1.AddCollisionEvent(cp2.m_localID, contact);
1400 //ctype = (int)CollisionCategories.Geom;
1401
1402 //if (cp1.CollidingObj)
1403 //cStartStop = (int)StatusIndicators.Generic;
1404 //else
1405 //cStartStop = (int)StatusIndicators.Start;
1406
1407 //returncollisions = true;
1408 }
1409 break;
1410
1411 case ActorTypes.Ground:
1412 case ActorTypes.Unknown:
1413 obj2LocalID = 0;
1414 //ctype = (int)CollisionCategories.Land;
1415
1416 //returncollisions = true;
1417 break;
1418 }
1419
1420 cp2.AddCollisionEvent(obj2LocalID, contact);
1421 }
1422 break;
1423 }
1424 //if (returncollisions)
1425 //{
1426
1427 //lock (m_storedCollisions)
1428 //{
1429 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1430 //if (m_storedCollisions.ContainsKey(cDictKey))
1431 //{
1432 //sCollisionData objd = m_storedCollisions[cDictKey];
1433 //objd.NumberOfCollisions += 1;
1434 //objd.lastframe = framecount;
1435 //m_storedCollisions[cDictKey] = objd;
1436 //}
1437 //else
1438 //{
1439 //sCollisionData objd = new sCollisionData();
1440 //objd.ColliderLocalId = obj1LocalID;
1441 //objd.CollidedWithLocalId = obj2LocalID;
1442 //objd.CollisionType = ctype;
1443 //objd.NumberOfCollisions = 1;
1444 //objd.lastframe = framecount;
1445 //objd.StatusIndicator = cStartStop;
1446 //m_storedCollisions.Add(cDictKey, objd);
1447 //}
1448 //}
1449 // }
1450 }
1451
1452 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1453 {
1454 /* String name1 = null;
1455 String name2 = null;
1456
1457 if (!geom_name_map.TryGetValue(trimesh, out name1))
1458 {
1459 name1 = "null";
1460 }
1461 if (!geom_name_map.TryGetValue(refObject, out name2))
1462 {
1463 name2 = "null";
1464 }
1465
1466 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1467 */
1468 return 1;
1469 }
1470
1471 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1472 {
1473 String name1 = null;
1474 String name2 = null;
1475
1476 if (!geom_name_map.TryGetValue(trimesh, out name1))
1477 {
1478 name1 = "null";
1479 }
1480
1481 if (!geom_name_map.TryGetValue(refObject, out name2))
1482 {
1483 name2 = "null";
1484 }
1485
1486 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1487
1488 d.Vector3 v0 = new d.Vector3();
1489 d.Vector3 v1 = new d.Vector3();
1490 d.Vector3 v2 = new d.Vector3();
1491
1492 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1493 // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
1494
1495 return 1;
1496 }
1497
1498 /// <summary>
1499 /// This is our collision testing routine in ODE
1500 /// </summary>
1501 /// <param name="timeStep"></param>
1502 private void collision_optimized(float timeStep)
1503 {
1504 _perloopContact.Clear();
1505
1506 lock (_characters)
1507 {
1508 foreach (OdeCharacter chr in _characters)
1509 {
1510 // Reset the collision values to false
1511 // since we don't know if we're colliding yet
1512
1513 // For some reason this can happen. Don't ask...
1514 //
1515 if (chr == null)
1516 continue;
1517
1518 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1519 continue;
1520
1521 chr.IsColliding = false;
1522 chr.CollidingGround = false;
1523 chr.CollidingObj = false;
1524
1525 // test the avatar's geometry for collision with the space
1526 // This will return near and the space that they are the closest to
1527 // And we'll run this again against the avatar and the space segment
1528 // This will return with a bunch of possible objects in the space segment
1529 // and we'll run it again on all of them.
1530 try
1531 {
1532 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1533 }
1534 catch (AccessViolationException)
1535 {
1536 m_log.Warn("[PHYSICS]: Unable to space collide");
1537 }
1538 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1539 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1540 //{
1541 //chr.Position.Z = terrainheight + 10.0f;
1542 //forcedZ = true;
1543 //}
1544 }
1545 }
1546
1547 lock (_activeprims)
1548 {
1549 List<OdePrim> removeprims = null;
1550 foreach (OdePrim chr in _activeprims)
1551 {
1552 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1553 {
1554 try
1555 {
1556 lock (chr)
1557 {
1558 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1559 {
1560 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1561 }
1562 else
1563 {
1564 if (removeprims == null)
1565 {
1566 removeprims = new List<OdePrim>();
1567 }
1568 removeprims.Add(chr);
1569 m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1570 }
1571 }
1572 }
1573 catch (AccessViolationException)
1574 {
1575 m_log.Warn("[PHYSICS]: Unable to space collide");
1576 }
1577 }
1578 }
1579 if (removeprims != null)
1580 {
1581 foreach (OdePrim chr in removeprims)
1582 {
1583 _activeprims.Remove(chr);
1584 }
1585 }
1586 }
1587
1588 _perloopContact.Clear();
1589 }
1590
1591 #endregion
1592
1593 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1594 {
1595 m_worldOffset = offset;
1596 WorldExtents = new Vector2(extents.X, extents.Y);
1597 m_parentScene = pScene;
1598
1599 }
1600
1601 // Recovered for use by fly height. Kitto Flora
1602 public float GetTerrainHeightAtXY(float x, float y)
1603 {
1604
1605 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1606 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1607
1608 IntPtr heightFieldGeom = IntPtr.Zero;
1609
1610 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1611 {
1612 if (heightFieldGeom != IntPtr.Zero)
1613 {
1614 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1615 {
1616
1617 int index;
1618
1619
1620 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1621 (int)x < 0.001f || (int)y < 0.001f)
1622 return 0;
1623
1624 x = x - offsetX;
1625 y = y - offsetY;
1626
1627 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1628
1629 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1630 {
1631 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1632 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1633 }
1634
1635 else
1636 return 0f;
1637 }
1638 else
1639 {
1640 return 0f;
1641 }
1642
1643 }
1644 else
1645 {
1646 return 0f;
1647 }
1648
1649 }
1650 else
1651 {
1652 return 0f;
1653 }
1654
1655
1656 }
1657// End recovered. Kitto Flora
1658
1659 public void addCollisionEventReporting(PhysicsActor obj)
1660 {
1661 lock (_collisionEventPrim)
1662 {
1663 if (!_collisionEventPrim.Contains(obj))
1664 _collisionEventPrim.Add(obj);
1665 }
1666 }
1667
1668 public void remCollisionEventReporting(PhysicsActor obj)
1669 {
1670 lock (_collisionEventPrim)
1671 {
1672 if (!_collisionEventPrim.Contains(obj))
1673 _collisionEventPrim.Remove(obj);
1674 }
1675 }
1676
1677 #region Add/Remove Entities
1678
1679 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1680 {
1681 Vector3 pos;
1682 pos.X = position.X;
1683 pos.Y = position.Y;
1684 pos.Z = position.Z;
1685 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1686 newAv.Flying = isFlying;
1687 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1688
1689 return newAv;
1690 }
1691
1692 public void AddCharacter(OdeCharacter chr)
1693 {
1694 lock (_characters)
1695 {
1696 if (!_characters.Contains(chr))
1697 {
1698 _characters.Add(chr);
1699 if (chr.bad)
1700 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1701 }
1702 }
1703 }
1704
1705 public void RemoveCharacter(OdeCharacter chr)
1706 {
1707 lock (_characters)
1708 {
1709 if (_characters.Contains(chr))
1710 {
1711 _characters.Remove(chr);
1712 }
1713 }
1714 }
1715 public void BadCharacter(OdeCharacter chr)
1716 {
1717 lock (_badCharacter)
1718 {
1719 if (!_badCharacter.Contains(chr))
1720 _badCharacter.Add(chr);
1721 }
1722 }
1723
1724 public override void RemoveAvatar(PhysicsActor actor)
1725 {
1726 //m_log.Debug("[PHYSICS]:ODELOCK");
1727 ((OdeCharacter) actor).Destroy();
1728
1729 }
1730
1731 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1732 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1733 {
1734
1735 Vector3 pos = position;
1736 Vector3 siz = size;
1737 Quaternion rot = rotation;
1738
1739 OdePrim newPrim;
1740 lock (OdeLock)
1741 {
1742 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1743
1744 lock (_prims)
1745 _prims.Add(newPrim);
1746 }
1747
1748 return newPrim;
1749 }
1750
1751 public void addActivePrim(OdePrim activatePrim)
1752 {
1753 // adds active prim.. (ones that should be iterated over in collisions_optimized
1754 lock (_activeprims)
1755 {
1756 if (!_activeprims.Contains(activatePrim))
1757 _activeprims.Add(activatePrim);
1758 //else
1759 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1760 }
1761 }
1762
1763 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1764 Vector3 size, Quaternion rotation) //To be removed
1765 {
1766 return AddPrimShape(primName, pbs, position, size, rotation, false);
1767 }
1768
1769 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1770 Vector3 size, Quaternion rotation, bool isPhysical)
1771 {
1772 PhysicsActor result;
1773 IMesh mesh = null;
1774
1775 if (needsMeshing(pbs))
1776 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1777
1778 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1779
1780 return result;
1781 }
1782
1783 public override float TimeDilation
1784 {
1785 get { return m_timeDilation; }
1786 }
1787
1788 public override bool SupportsNINJAJoints
1789 {
1790 get { return m_NINJA_physics_joints_enabled; }
1791 }
1792
1793 // internal utility function: must be called within a lock (OdeLock)
1794 private void InternalAddActiveJoint(PhysicsJoint joint)
1795 {
1796 activeJoints.Add(joint);
1797 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1798 }
1799
1800 // internal utility function: must be called within a lock (OdeLock)
1801 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1802 {
1803 pendingJoints.Add(joint);
1804 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1805 }
1806
1807 // internal utility function: must be called within a lock (OdeLock)
1808 private void InternalRemovePendingJoint(PhysicsJoint joint)
1809 {
1810 pendingJoints.Remove(joint);
1811 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1812 }
1813
1814 // internal utility function: must be called within a lock (OdeLock)
1815 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1816 {
1817 activeJoints.Remove(joint);
1818 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1819 }
1820
1821 public override void DumpJointInfo()
1822 {
1823 string hdr = "[NINJA] JOINTINFO: ";
1824 foreach (PhysicsJoint j in pendingJoints)
1825 {
1826 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1827 }
1828 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1829 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1830 {
1831 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1832 }
1833 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1834 foreach (PhysicsJoint j in activeJoints)
1835 {
1836 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1837 }
1838 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1839 foreach (string jointName in SOPName_to_activeJoint.Keys)
1840 {
1841 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1842 }
1843 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1844
1845 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1846 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1847 foreach (string actorName in joints_connecting_actor.Keys)
1848 {
1849 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1850 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1851 {
1852 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1853 }
1854 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1855 }
1856 }
1857
1858 public override void RequestJointDeletion(string ObjectNameInScene)
1859 {
1860 lock (externalJointRequestsLock)
1861 {
1862 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1863 {
1864 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1865 }
1866 }
1867 }
1868
1869 private void DeleteRequestedJoints()
1870 {
1871 List<string> myRequestedJointsToBeDeleted;
1872 lock (externalJointRequestsLock)
1873 {
1874 // make a local copy of the shared list for processing (threading issues)
1875 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1876 }
1877
1878 foreach (string jointName in myRequestedJointsToBeDeleted)
1879 {
1880 lock (OdeLock)
1881 {
1882 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1883 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1884 {
1885 OdePhysicsJoint joint = null;
1886 if (SOPName_to_activeJoint.ContainsKey(jointName))
1887 {
1888 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1889 InternalRemoveActiveJoint(joint);
1890 }
1891 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1892 {
1893 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1894 InternalRemovePendingJoint(joint);
1895 }
1896
1897 if (joint != null)
1898 {
1899 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1900 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1901 {
1902 string bodyName = joint.BodyNames[iBodyName];
1903 if (bodyName != "NULL")
1904 {
1905 joints_connecting_actor[bodyName].Remove(joint);
1906 if (joints_connecting_actor[bodyName].Count == 0)
1907 {
1908 joints_connecting_actor.Remove(bodyName);
1909 }
1910 }
1911 }
1912
1913 DoJointDeactivated(joint);
1914 if (joint.jointID != IntPtr.Zero)
1915 {
1916 d.JointDestroy(joint.jointID);
1917 joint.jointID = IntPtr.Zero;
1918 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1919 }
1920 else
1921 {
1922 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1923 }
1924 }
1925 else
1926 {
1927 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1928 }
1929 }
1930 else
1931 {
1932 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1933 }
1934 }
1935 }
1936
1937 // remove processed joints from the shared list
1938 lock (externalJointRequestsLock)
1939 {
1940 foreach (string jointName in myRequestedJointsToBeDeleted)
1941 {
1942 requestedJointsToBeDeleted.Remove(jointName);
1943 }
1944 }
1945 }
1946
1947 // for pending joints we don't know if their associated bodies exist yet or not.
1948 // the joint is actually created during processing of the taints
1949 private void CreateRequestedJoints()
1950 {
1951 List<PhysicsJoint> myRequestedJointsToBeCreated;
1952 lock (externalJointRequestsLock)
1953 {
1954 // make a local copy of the shared list for processing (threading issues)
1955 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1956 }
1957
1958 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1959 {
1960 lock (OdeLock)
1961 {
1962 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1963 {
1964 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1965 continue;
1966 }
1967 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1968 {
1969 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1970 continue;
1971 }
1972
1973 InternalAddPendingJoint(joint as OdePhysicsJoint);
1974
1975 if (joint.BodyNames.Count >= 2)
1976 {
1977 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1978 {
1979 string bodyName = joint.BodyNames[iBodyName];
1980 if (bodyName != "NULL")
1981 {
1982 if (!joints_connecting_actor.ContainsKey(bodyName))
1983 {
1984 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1985 }
1986 joints_connecting_actor[bodyName].Add(joint);
1987 }
1988 }
1989 }
1990 }
1991 }
1992
1993 // remove processed joints from shared list
1994 lock (externalJointRequestsLock)
1995 {
1996 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1997 {
1998 requestedJointsToBeCreated.Remove(joint);
1999 }
2000 }
2001
2002 }
2003
2004 // public function to add an request for joint creation
2005 // this joint will just be added to a waiting list that is NOT processed during the main
2006 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2007
2008 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2009 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2010
2011 {
2012
2013 OdePhysicsJoint joint = new OdePhysicsJoint();
2014 joint.ObjectNameInScene = objectNameInScene;
2015 joint.Type = jointType;
2016 joint.Position = position;
2017 joint.Rotation = rotation;
2018 joint.RawParams = parms;
2019 joint.BodyNames = new List<string>(bodyNames);
2020 joint.TrackedBodyName = trackedBodyName;
2021 joint.LocalRotation = localRotation;
2022 joint.jointID = IntPtr.Zero;
2023 joint.ErrorMessageCount = 0;
2024
2025 lock (externalJointRequestsLock)
2026 {
2027 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2028 {
2029 requestedJointsToBeCreated.Add(joint);
2030 }
2031 }
2032 return joint;
2033 }
2034
2035 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2036 {
2037 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2038 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2039 {
2040
2041 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2042 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2043 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2044 {
2045 jointsToRemove.Add(j);
2046 }
2047 foreach (PhysicsJoint j in jointsToRemove)
2048 {
2049 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2050 RequestJointDeletion(j.ObjectNameInScene);
2051 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2052 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2053 }
2054 }
2055 }
2056
2057 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2058 {
2059 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2060 lock (OdeLock)
2061 {
2062 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2063 RemoveAllJointsConnectedToActor(actor);
2064 }
2065 }
2066
2067 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2068 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2069 {
2070 Debug.Assert(joint.IsInPhysicsEngine);
2071 d.Vector3 pos = new d.Vector3();
2072
2073 if (!(joint is OdePhysicsJoint))
2074 {
2075 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2076 }
2077 else
2078 {
2079 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2080 switch (odeJoint.Type)
2081 {
2082 case PhysicsJointType.Ball:
2083 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2084 break;
2085 case PhysicsJointType.Hinge:
2086 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2087 break;
2088 }
2089 }
2090 return new Vector3(pos.X, pos.Y, pos.Z);
2091 }
2092
2093 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2094 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2095 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2096 // keeping track of the joint's original orientation relative to one of the involved bodies.
2097 public override Vector3 GetJointAxis(PhysicsJoint joint)
2098 {
2099 Debug.Assert(joint.IsInPhysicsEngine);
2100 d.Vector3 axis = new d.Vector3();
2101
2102 if (!(joint is OdePhysicsJoint))
2103 {
2104 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2105 }
2106 else
2107 {
2108 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2109 switch (odeJoint.Type)
2110 {
2111 case PhysicsJointType.Ball:
2112 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2113 break;
2114 case PhysicsJointType.Hinge:
2115 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2116 break;
2117 }
2118 }
2119 return new Vector3(axis.X, axis.Y, axis.Z);
2120 }
2121
2122
2123 public void remActivePrim(OdePrim deactivatePrim)
2124 {
2125 lock (_activeprims)
2126 {
2127 _activeprims.Remove(deactivatePrim);
2128 }
2129 }
2130
2131 public override void RemovePrim(PhysicsActor prim)
2132 {
2133 if (prim is OdePrim)
2134 {
2135 lock (OdeLock)
2136 {
2137 OdePrim p = (OdePrim) prim;
2138
2139 p.setPrimForRemoval();
2140 AddPhysicsActorTaint(prim);
2141 //RemovePrimThreadLocked(p);
2142 }
2143 }
2144 }
2145
2146 /// <summary>
2147 /// This is called from within simulate but outside the locked portion
2148 /// We need to do our own locking here
2149 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2150 ///
2151 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2152 /// that the space was using.
2153 /// </summary>
2154 /// <param name="prim"></param>
2155 public void RemovePrimThreadLocked(OdePrim prim)
2156 {
2157//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2158 lock (prim)
2159 {
2160 remCollisionEventReporting(prim);
2161 lock (ode)
2162 {
2163 if (prim.prim_geom != IntPtr.Zero)
2164 {
2165 prim.ResetTaints();
2166
2167 if (prim.IsPhysical)
2168 {
2169 prim.disableBody();
2170 if (prim.childPrim)
2171 {
2172 prim.childPrim = false;
2173 prim.Body = IntPtr.Zero;
2174 prim.m_disabled = true;
2175 prim.IsPhysical = false;
2176 }
2177
2178
2179 }
2180 // we don't want to remove the main space
2181
2182 // If the geometry is in the targetspace, remove it from the target space
2183 //m_log.Warn(prim.m_targetSpace);
2184
2185 //if (prim.m_targetSpace != IntPtr.Zero)
2186 //{
2187 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2188 //{
2189
2190 //if (d.GeomIsSpace(prim.m_targetSpace))
2191 //{
2192 //waitForSpaceUnlock(prim.m_targetSpace);
2193 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2194 prim.m_targetSpace = IntPtr.Zero;
2195 //}
2196 //else
2197 //{
2198 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2199 //((OdePrim)prim).m_targetSpace.ToString());
2200 //}
2201
2202 //}
2203 //}
2204 //m_log.Warn(prim.prim_geom);
2205 try
2206 {
2207 if (prim.prim_geom != IntPtr.Zero)
2208 {
2209
2210//string tPA;
2211//geom_name_map.TryGetValue(prim.prim_geom, out tPA);
2212//Console.WriteLine("**** Remove {0}", tPA);
2213 if(geom_name_map.ContainsKey(prim.prim_geom)) geom_name_map.Remove(prim.prim_geom);
2214 if(actor_name_map.ContainsKey(prim.prim_geom)) actor_name_map.Remove(prim.prim_geom);
2215 d.GeomDestroy(prim.prim_geom);
2216 prim.prim_geom = IntPtr.Zero;
2217 }
2218 else
2219 {
2220 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2221 }
2222 }
2223 catch (AccessViolationException)
2224 {
2225 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2226 }
2227 lock (_prims)
2228 _prims.Remove(prim);
2229
2230 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2231 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2232 //{
2233 //if (prim.m_targetSpace != null)
2234 //{
2235 //if (d.GeomIsSpace(prim.m_targetSpace))
2236 //{
2237 //waitForSpaceUnlock(prim.m_targetSpace);
2238 //d.SpaceRemove(space, prim.m_targetSpace);
2239 // free up memory used by the space.
2240 //d.SpaceDestroy(prim.m_targetSpace);
2241 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2242 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2243 //}
2244 //else
2245 //{
2246 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2247 //((OdePrim) prim).m_targetSpace.ToString());
2248 //}
2249 //}
2250 //}
2251
2252 if (SupportsNINJAJoints)
2253 {
2254 RemoveAllJointsConnectedToActorThreadLocked(prim);
2255 }
2256 }
2257 }
2258 }
2259 }
2260
2261 #endregion
2262
2263 #region Space Separation Calculation
2264
2265 /// <summary>
2266 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2267 /// </summary>
2268 /// <param name="pSpace"></param>
2269 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2270 {
2271 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2272 {
2273 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2274 {
2275 if (staticPrimspace[x, y] == pSpace)
2276 staticPrimspace[x, y] = IntPtr.Zero;
2277 }
2278 }
2279 }
2280
2281 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2282 {
2283 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2284 }
2285
2286 /// <summary>
2287 /// Called when a static prim moves. Allocates a space for the prim based on its position
2288 /// </summary>
2289 /// <param name="geom">the pointer to the geom that moved</param>
2290 /// <param name="pos">the position that the geom moved to</param>
2291 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2292 /// <returns>a pointer to the new space it's in</returns>
2293 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2294 {
2295 // Called from setting the Position and Size of an ODEPrim so
2296 // it's already in locked space.
2297
2298 // we don't want to remove the main space
2299 // we don't need to test physical here because this function should
2300 // never be called if the prim is physical(active)
2301
2302 // All physical prim end up in the root space
2303 //Thread.Sleep(20);
2304 if (currentspace != space)
2305 {
2306 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2307 //if (currentspace == IntPtr.Zero)
2308 //{
2309 //int adfadf = 0;
2310 //}
2311 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2312 {
2313 if (d.GeomIsSpace(currentspace))
2314 {
2315 waitForSpaceUnlock(currentspace);
2316 d.SpaceRemove(currentspace, geom);
2317 }
2318 else
2319 {
2320 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2321 " Geom:" + geom);
2322 }
2323 }
2324 else
2325 {
2326 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2327 if (sGeomIsIn != IntPtr.Zero)
2328 {
2329 if (d.GeomIsSpace(currentspace))
2330 {
2331 waitForSpaceUnlock(sGeomIsIn);
2332 d.SpaceRemove(sGeomIsIn, geom);
2333 }
2334 else
2335 {
2336 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2337 sGeomIsIn + " Geom:" + geom);
2338 }
2339 }
2340 }
2341
2342 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2343 if (d.SpaceGetNumGeoms(currentspace) == 0)
2344 {
2345 if (currentspace != IntPtr.Zero)
2346 {
2347 if (d.GeomIsSpace(currentspace))
2348 {
2349 waitForSpaceUnlock(currentspace);
2350 waitForSpaceUnlock(space);
2351 d.SpaceRemove(space, currentspace);
2352 // free up memory used by the space.
2353
2354 //d.SpaceDestroy(currentspace);
2355 resetSpaceArrayItemToZero(currentspace);
2356 }
2357 else
2358 {
2359 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2360 currentspace + " Geom:" + geom);
2361 }
2362 }
2363 }
2364 }
2365 else
2366 {
2367 // this is a physical object that got disabled. ;.;
2368 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2369 {
2370 if (d.SpaceQuery(currentspace, geom))
2371 {
2372 if (d.GeomIsSpace(currentspace))
2373 {
2374 waitForSpaceUnlock(currentspace);
2375 d.SpaceRemove(currentspace, geom);
2376 }
2377 else
2378 {
2379 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2380 currentspace + " Geom:" + geom);
2381 }
2382 }
2383 else
2384 {
2385 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2386 if (sGeomIsIn != IntPtr.Zero)
2387 {
2388 if (d.GeomIsSpace(sGeomIsIn))
2389 {
2390 waitForSpaceUnlock(sGeomIsIn);
2391 d.SpaceRemove(sGeomIsIn, geom);
2392 }
2393 else
2394 {
2395 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2396 sGeomIsIn + " Geom:" + geom);
2397 }
2398 }
2399 }
2400 }
2401 }
2402
2403 // The routines in the Position and Size sections do the 'inserting' into the space,
2404 // so all we have to do is make sure that the space that we're putting the prim into
2405 // is in the 'main' space.
2406 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2407 IntPtr newspace = calculateSpaceForGeom(pos);
2408
2409 if (newspace == IntPtr.Zero)
2410 {
2411 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2412 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2413 }
2414
2415 return newspace;
2416 }
2417
2418 /// <summary>
2419 /// Creates a new space at X Y
2420 /// </summary>
2421 /// <param name="iprimspaceArrItemX"></param>
2422 /// <param name="iprimspaceArrItemY"></param>
2423 /// <returns>A pointer to the created space</returns>
2424 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2425 {
2426 // creating a new space for prim and inserting it into main space.
2427 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2428 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2429 waitForSpaceUnlock(space);
2430 d.SpaceSetSublevel(space, 1);
2431 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2432 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2433 }
2434
2435 /// <summary>
2436 /// Calculates the space the prim should be in by its position
2437 /// </summary>
2438 /// <param name="pos"></param>
2439 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2440 public IntPtr calculateSpaceForGeom(Vector3 pos)
2441 {
2442 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2443 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2444 return staticPrimspace[xyspace[0], xyspace[1]];
2445 }
2446
2447 /// <summary>
2448 /// Holds the space allocation logic
2449 /// </summary>
2450 /// <param name="pos"></param>
2451 /// <returns>an array item based on the position</returns>
2452 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2453 {
2454 int[] returnint = new int[2];
2455
2456 returnint[0] = (int) (pos.X/metersInSpace);
2457
2458 if (returnint[0] > ((int) (259f/metersInSpace)))
2459 returnint[0] = ((int) (259f/metersInSpace));
2460 if (returnint[0] < 0)
2461 returnint[0] = 0;
2462
2463 returnint[1] = (int) (pos.Y/metersInSpace);
2464 if (returnint[1] > ((int) (259f/metersInSpace)))
2465 returnint[1] = ((int) (259f/metersInSpace));
2466 if (returnint[1] < 0)
2467 returnint[1] = 0;
2468
2469 return returnint;
2470 }
2471
2472 #endregion
2473
2474 /// <summary>
2475 /// Routine to figure out if we need to mesh this prim with our mesher
2476 /// </summary>
2477 /// <param name="pbs"></param>
2478 /// <returns></returns>
2479 public bool needsMeshing(PrimitiveBaseShape pbs)
2480 {
2481 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2482 // but we still need to check for sculptie meshing being enabled so this is the most
2483 // convenient place to do it for now...
2484
2485 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2486 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2487 int iPropertiesNotSupportedDefault = 0;
2488
2489 if (pbs.SculptEntry && !meshSculptedPrim)
2490 {
2491#if SPAM
2492 m_log.Warn("NonMesh");
2493#endif
2494 return false;
2495 }
2496
2497 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
2498 if (!forceSimplePrimMeshing)
2499 {
2500 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2501 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2502 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2503 {
2504
2505 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2506 && pbs.ProfileHollow == 0
2507 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2508 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2509 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2510 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2511 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2512 {
2513#if SPAM
2514 m_log.Warn("NonMesh");
2515#endif
2516 return false;
2517 }
2518 }
2519 }
2520
2521 if (pbs.ProfileHollow != 0)
2522 iPropertiesNotSupportedDefault++;
2523
2524 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2525 iPropertiesNotSupportedDefault++;
2526
2527 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2528 iPropertiesNotSupportedDefault++;
2529
2530 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2531 iPropertiesNotSupportedDefault++;
2532
2533 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2534 iPropertiesNotSupportedDefault++;
2535
2536 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2537 iPropertiesNotSupportedDefault++;
2538
2539 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
2540 iPropertiesNotSupportedDefault++;
2541
2542 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2543 iPropertiesNotSupportedDefault++;
2544
2545 // test for torus
2546 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2547 {
2548 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2549 {
2550 iPropertiesNotSupportedDefault++;
2551 }
2552 }
2553 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2554 {
2555 if (pbs.PathCurve == (byte)Extrusion.Straight)
2556 {
2557 iPropertiesNotSupportedDefault++;
2558 }
2559
2560 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2561 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2562 {
2563 iPropertiesNotSupportedDefault++;
2564 }
2565 }
2566 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2567 {
2568 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2569 {
2570 iPropertiesNotSupportedDefault++;
2571 }
2572 }
2573 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2574 {
2575 if (pbs.PathCurve == (byte)Extrusion.Straight)
2576 {
2577 iPropertiesNotSupportedDefault++;
2578 }
2579 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2580 {
2581 iPropertiesNotSupportedDefault++;
2582 }
2583 }
2584
2585
2586 if (iPropertiesNotSupportedDefault == 0)
2587 {
2588#if SPAM
2589 m_log.Warn("NonMesh");
2590#endif
2591 return false;
2592 }
2593#if SPAM
2594 m_log.Debug("Mesh");
2595#endif
2596 return true;
2597 }
2598
2599 /// <summary>
2600 /// Called after our prim properties are set Scale, position etc.
2601 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2602 /// This assures us that we have no race conditions
2603 /// </summary>
2604 /// <param name="prim"></param>
2605 public override void AddPhysicsActorTaint(PhysicsActor prim)
2606 {
2607
2608 if (prim is OdePrim)
2609 {
2610 OdePrim taintedprim = ((OdePrim) prim);
2611 lock (_taintedPrimLock)
2612 {
2613 if (!(_taintedPrimH.Contains(taintedprim)))
2614 {
2615//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2616 _taintedPrimH.Add(taintedprim); // HashSet for searching
2617 _taintedPrimL.Add(taintedprim); // List for ordered readout
2618 }
2619 }
2620 return;
2621 }
2622 else if (prim is OdeCharacter)
2623 {
2624 OdeCharacter taintedchar = ((OdeCharacter)prim);
2625 lock (_taintedActors)
2626 {
2627 if (!(_taintedActors.Contains(taintedchar)))
2628 {
2629 _taintedActors.Add(taintedchar);
2630 if (taintedchar.bad)
2631 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2632 }
2633 }
2634 }
2635 }
2636
2637 /// <summary>
2638 /// This is our main simulate loop
2639 /// It's thread locked by a Mutex in the scene.
2640 /// It holds Collisions, it instructs ODE to step through the physical reactions
2641 /// It moves the objects around in memory
2642 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2643 /// </summary>
2644 /// <param name="timeStep"></param>
2645 /// <returns></returns>
2646 public override float Simulate(float timeStep)
2647 {
2648 if (framecount >= int.MaxValue)
2649 framecount = 0;
2650 //if (m_worldOffset != Vector3.Zero)
2651 // return 0;
2652
2653 framecount++;
2654
2655 DateTime now = DateTime.UtcNow;
2656 TimeSpan SinceLastFrame = now - m_lastframe;
2657 m_lastframe = now;
2658 float realtime = (float)SinceLastFrame.TotalSeconds;
2659// Console.WriteLine("ts={0} rt={1}", timeStep, realtime);
2660 timeStep = realtime;
2661
2662 // float fps = 1.0f / realtime;
2663 float fps = 0.0f; // number of ODE steps in this Simulate step
2664 //m_log.Info(timeStep.ToString());
2665 step_time += timeStep;
2666
2667 // If We're loaded down by something else,
2668 // or debugging with the Visual Studio project on pause
2669 // skip a few frames to catch up gracefully.
2670 // without shooting the physicsactors all over the place
2671
2672 if (step_time >= m_SkipFramesAtms)
2673 {
2674 // Instead of trying to catch up, it'll do 5 physics frames only
2675 step_time = ODE_STEPSIZE;
2676 m_physicsiterations = 5;
2677 }
2678 else
2679 {
2680 m_physicsiterations = 10;
2681 }
2682
2683 if (SupportsNINJAJoints)
2684 {
2685 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2686 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2687 }
2688
2689 lock (OdeLock)
2690 {
2691 // Process 10 frames if the sim is running normal..
2692 // process 5 frames if the sim is running slow
2693 //try
2694 //{
2695 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2696 //}
2697 //catch (StackOverflowException)
2698 //{
2699 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2700 // ode.drelease(world);
2701 //base.TriggerPhysicsBasedRestart();
2702 //}
2703
2704 int i = 0;
2705
2706 // Figure out the Frames Per Second we're going at.
2707 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2708
2709 // fps = (step_time / ODE_STEPSIZE) * 1000;
2710 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2711 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2712
2713 // step_time = 0.09375f;
2714
2715 while (step_time > 0.0f)
2716 {
2717 //lock (ode)
2718 //{
2719 //if (!ode.lockquery())
2720 //{
2721 // ode.dlock(world);
2722 try
2723 {
2724 // Insert, remove Characters
2725 bool processedtaints = false;
2726
2727 lock (_taintedActors)
2728 {
2729 if (_taintedActors.Count > 0)
2730 {
2731 foreach (OdeCharacter character in _taintedActors)
2732 {
2733
2734 character.ProcessTaints(ODE_STEPSIZE);
2735
2736 processedtaints = true;
2737 //character.m_collisionscore = 0;
2738 }
2739
2740 if (processedtaints)
2741 _taintedActors.Clear();
2742 }
2743 } // end lock _taintedActors
2744
2745 // Modify other objects in the scene.
2746 processedtaints = false;
2747
2748 lock (_taintedPrimLock)
2749 {
2750 foreach (OdePrim prim in _taintedPrimL)
2751 {
2752 if (prim.m_taintremove)
2753 {
2754 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2755 RemovePrimThreadLocked(prim);
2756 }
2757 else
2758 {
2759 //Console.WriteLine("Simulate calls ProcessTaints");
2760 prim.ProcessTaints(ODE_STEPSIZE);
2761 }
2762 processedtaints = true;
2763 prim.m_collisionscore = 0;
2764
2765 // This loop can block up the Heartbeat for a very long time on large regions.
2766 // We need to let the Watchdog know that the Heartbeat is not dead
2767 // NOTE: This is currently commented out, but if things like OAR loading are
2768 // timing the heartbeat out we will need to uncomment it
2769 //Watchdog.UpdateThread();
2770 }
2771
2772 if (SupportsNINJAJoints)
2773 {
2774 // Create pending joints, if possible
2775
2776 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2777 // a joint requires specifying the body id of both involved bodies
2778 if (pendingJoints.Count > 0)
2779 {
2780 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2781 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2782 foreach (PhysicsJoint joint in pendingJoints)
2783 {
2784 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2785 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(),
2786 System.StringSplitOptions.RemoveEmptyEntries);
2787 List<IntPtr> jointBodies = new List<IntPtr>();
2788 bool allJointBodiesAreReady = true;
2789 foreach (string jointParam in jointParams)
2790 {
2791 if (jointParam == "NULL")
2792 {
2793 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2794 jointBodies.Add(IntPtr.Zero);
2795 }
2796 else
2797 {
2798 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2799 bool foundPrim = false;
2800 lock (_prims)
2801 {
2802 foreach (OdePrim prim in _prims) // FIXME: inefficient
2803 {
2804 if (prim.SOPName == jointParam)
2805 {
2806 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2807 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2808 {
2809 jointBodies.Add(prim.Body);
2810 foundPrim = true;
2811 break;
2812 }
2813 else
2814 {
2815 DoJointErrorMessage(joint, "prim name " + jointParam +
2816 " exists but is not (yet) physical; deferring joint creation. " +
2817 "IsPhysical property is " + prim.IsPhysical +
2818 " and body is " + prim.Body);
2819 foundPrim = false;
2820 break;
2821 }
2822 }
2823 }
2824 }
2825 if (foundPrim)
2826 {
2827 // all is fine
2828 }
2829 else
2830 {
2831 allJointBodiesAreReady = false;
2832 break;
2833 }
2834 }
2835 }
2836 if (allJointBodiesAreReady)
2837 {
2838 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2839 if (jointBodies[0] == jointBodies[1])
2840 {
2841 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2842 }
2843 else
2844 {
2845 switch (joint.Type)
2846 {
2847 case PhysicsJointType.Ball:
2848 {
2849 IntPtr odeJoint;
2850 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2851 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2852 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2853 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2854 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2855 d.JointSetBallAnchor(odeJoint,
2856 joint.Position.X,
2857 joint.Position.Y,
2858 joint.Position.Z);
2859 //DoJointErrorMessage(joint, "ODE joint setting OK");
2860 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2861 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2862 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2863 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2864
2865 if (joint is OdePhysicsJoint)
2866 {
2867 ((OdePhysicsJoint)joint).jointID = odeJoint;
2868 }
2869 else
2870 {
2871 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2872 }
2873 }
2874 break;
2875 case PhysicsJointType.Hinge:
2876 {
2877 IntPtr odeJoint;
2878 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2879 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2880 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2881 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2882 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2883 d.JointSetHingeAnchor(odeJoint,
2884 joint.Position.X,
2885 joint.Position.Y,
2886 joint.Position.Z);
2887 // We use the orientation of the x-axis of the joint's coordinate frame
2888 // as the axis for the hinge.
2889
2890 // Therefore, we must get the joint's coordinate frame based on the
2891 // joint.Rotation field, which originates from the orientation of the
2892 // joint's proxy object in the scene.
2893
2894 // The joint's coordinate frame is defined as the transformation matrix
2895 // that converts a vector from joint-local coordinates into world coordinates.
2896 // World coordinates are defined as the XYZ coordinate system of the sim,
2897 // as shown in the top status-bar of the viewer.
2898
2899 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2900 // and use that as the hinge axis.
2901
2902 //joint.Rotation.Normalize();
2903 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2904
2905 // Now extract the X axis of the joint's coordinate frame.
2906
2907 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2908 // tar pit of transposed, inverted, and generally messed-up orientations.
2909 // (In other words, Matrix4.AtAxis() is borked.)
2910 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2911
2912 // Instead, compute the X axis of the coordinate frame by transforming
2913 // the (1,0,0) vector. At least that works.
2914
2915 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2916 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2917 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2918 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2919 d.JointSetHingeAxis(odeJoint,
2920 jointAxis.X,
2921 jointAxis.Y,
2922 jointAxis.Z);
2923 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2924 if (joint is OdePhysicsJoint)
2925 {
2926 ((OdePhysicsJoint)joint).jointID = odeJoint;
2927 }
2928 else
2929 {
2930 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2931 }
2932 }
2933 break;
2934 }
2935 successfullyProcessedPendingJoints.Add(joint);
2936 }
2937 }
2938 else
2939 {
2940 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2941 }
2942 }
2943 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2944 {
2945 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2946 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2947 InternalRemovePendingJoint(successfullyProcessedJoint);
2948 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2949 InternalAddActiveJoint(successfullyProcessedJoint);
2950 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2951 }
2952 }
2953 } // end SupportsNINJAJoints
2954
2955 if (processedtaints)
2956//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2957 _taintedPrimH.Clear(); // ??? if this only ???
2958 _taintedPrimL.Clear();
2959 } // end lock _taintedPrimLock
2960
2961 // Move characters
2962 lock (_characters)
2963 {
2964 List<OdeCharacter> defects = new List<OdeCharacter>();
2965 foreach (OdeCharacter actor in _characters)
2966 {
2967 if (actor != null)
2968 actor.Move(ODE_STEPSIZE, defects);
2969 }
2970 if (0 != defects.Count)
2971 {
2972 foreach (OdeCharacter defect in defects)
2973 {
2974 RemoveCharacter(defect);
2975 }
2976 }
2977 } // end lock _characters
2978
2979 // Move other active objects
2980 lock (_activeprims)
2981 {
2982 foreach (OdePrim prim in _activeprims)
2983 {
2984 prim.m_collisionscore = 0;
2985 prim.Move(ODE_STEPSIZE);
2986 }
2987 } // end lock _activeprims
2988
2989 //if ((framecount % m_randomizeWater) == 0)
2990 // randomizeWater(waterlevel);
2991
2992 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2993 m_rayCastManager.ProcessQueuedRequests();
2994
2995 collision_optimized(ODE_STEPSIZE);
2996
2997 lock (_collisionEventPrim)
2998 {
2999 foreach (PhysicsActor obj in _collisionEventPrim)
3000 {
3001 if (obj == null)
3002 continue;
3003
3004 switch ((ActorTypes)obj.PhysicsActorType)
3005 {
3006 case ActorTypes.Agent:
3007 OdeCharacter cobj = (OdeCharacter)obj;
3008 cobj.AddCollisionFrameTime(100);
3009 cobj.SendCollisions();
3010 break;
3011 case ActorTypes.Prim:
3012 OdePrim pobj = (OdePrim)obj;
3013 pobj.SendCollisions();
3014 break;
3015 }
3016 }
3017 } // end lock _collisionEventPrim
3018
3019 //if (m_global_contactcount > 5)
3020 //{
3021 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3022 //}
3023
3024 m_global_contactcount = 0;
3025
3026 d.WorldQuickStep(world, ODE_STEPSIZE);
3027 d.JointGroupEmpty(contactgroup);
3028 fps++;
3029 //ode.dunlock(world);
3030 } // end try
3031 catch (Exception e)
3032 {
3033 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3034 ode.dunlock(world);
3035 }
3036
3037 step_time -= ODE_STEPSIZE;
3038 i++;
3039 //}
3040 //else
3041 //{
3042 //fps = 0;
3043 //}
3044 //}
3045 } // end while (step_time > 0.0f)
3046
3047 lock (_characters)
3048 {
3049 foreach (OdeCharacter actor in _characters)
3050 {
3051 if (actor != null)
3052 {
3053 if (actor.bad)
3054 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3055 actor.UpdatePositionAndVelocity();
3056 }
3057 }
3058 }
3059
3060 lock (_badCharacter)
3061 {
3062 if (_badCharacter.Count > 0)
3063 {
3064 foreach (OdeCharacter chr in _badCharacter)
3065 {
3066 RemoveCharacter(chr);
3067 }
3068 _badCharacter.Clear();
3069 }
3070 }
3071
3072 lock (_activeprims)
3073 {
3074 //if (timeStep < 0.2f)
3075 {
3076 foreach (OdePrim actor in _activeprims)
3077 {
3078 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3079 {
3080 actor.UpdatePositionAndVelocity();
3081
3082 if (SupportsNINJAJoints)
3083 {
3084 // If an actor moved, move its joint proxy objects as well.
3085 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3086 // for this purpose but it is never called! So we just do the joint
3087 // movement code here.
3088
3089 if (actor.SOPName != null &&
3090 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3091 joints_connecting_actor[actor.SOPName] != null &&
3092 joints_connecting_actor[actor.SOPName].Count > 0)
3093 {
3094 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3095 {
3096 if (affectedJoint.IsInPhysicsEngine)
3097 {
3098 DoJointMoved(affectedJoint);
3099 }
3100 else
3101 {
3102 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3103 }
3104 }
3105 }
3106 }
3107 }
3108 }
3109 }
3110 } // end lock _activeprims
3111
3112 //DumpJointInfo();
3113
3114 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3115 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3116 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3117 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3118 {
3119 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3120 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3121
3122 if (physics_logging_append_existing_logfile)
3123 {
3124 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3125 TextWriter fwriter = File.AppendText(fname);
3126 fwriter.WriteLine(header);
3127 fwriter.Close();
3128 }
3129 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3130 }
3131 } // end lock OdeLock
3132
3133 return fps * 1000.0f; //NB This is a FRAME COUNT, not a time! AND is divide by 1000 in SimStatusReporter!
3134 } // end Simulate
3135
3136 public override void GetResults()
3137 {
3138 }
3139
3140 public override bool IsThreaded
3141 {
3142 // for now we won't be multithreaded
3143 get { return (false); }
3144 }
3145
3146 #region ODE Specific Terrain Fixes
3147 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3148 {
3149 float[] returnarr = new float[262144];
3150 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3151
3152 // Filling out the array into its multi-dimensional components
3153 for (int y = 0; y < WorldExtents.Y; y++)
3154 {
3155 for (int x = 0; x < WorldExtents.X; x++)
3156 {
3157 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3158 }
3159 }
3160
3161 // Resize using Nearest Neighbour
3162
3163 // This particular way is quick but it only works on a multiple of the original
3164
3165 // The idea behind this method can be described with the following diagrams
3166 // second pass and third pass happen in the same loop really.. just separated
3167 // them to show what this does.
3168
3169 // First Pass
3170 // ResultArr:
3171 // 1,1,1,1,1,1
3172 // 1,1,1,1,1,1
3173 // 1,1,1,1,1,1
3174 // 1,1,1,1,1,1
3175 // 1,1,1,1,1,1
3176 // 1,1,1,1,1,1
3177
3178 // Second Pass
3179 // ResultArr2:
3180 // 1,,1,,1,,1,,1,,1,
3181 // ,,,,,,,,,,
3182 // 1,,1,,1,,1,,1,,1,
3183 // ,,,,,,,,,,
3184 // 1,,1,,1,,1,,1,,1,
3185 // ,,,,,,,,,,
3186 // 1,,1,,1,,1,,1,,1,
3187 // ,,,,,,,,,,
3188 // 1,,1,,1,,1,,1,,1,
3189 // ,,,,,,,,,,
3190 // 1,,1,,1,,1,,1,,1,
3191
3192 // Third pass fills in the blanks
3193 // ResultArr2:
3194 // 1,1,1,1,1,1,1,1,1,1,1,1
3195 // 1,1,1,1,1,1,1,1,1,1,1,1
3196 // 1,1,1,1,1,1,1,1,1,1,1,1
3197 // 1,1,1,1,1,1,1,1,1,1,1,1
3198 // 1,1,1,1,1,1,1,1,1,1,1,1
3199 // 1,1,1,1,1,1,1,1,1,1,1,1
3200 // 1,1,1,1,1,1,1,1,1,1,1,1
3201 // 1,1,1,1,1,1,1,1,1,1,1,1
3202 // 1,1,1,1,1,1,1,1,1,1,1,1
3203 // 1,1,1,1,1,1,1,1,1,1,1,1
3204 // 1,1,1,1,1,1,1,1,1,1,1,1
3205
3206 // X,Y = .
3207 // X+1,y = ^
3208 // X,Y+1 = *
3209 // X+1,Y+1 = #
3210
3211 // Filling in like this;
3212 // .*
3213 // ^#
3214 // 1st .
3215 // 2nd *
3216 // 3rd ^
3217 // 4th #
3218 // on single loop.
3219
3220 float[,] resultarr2 = new float[512, 512];
3221 for (int y = 0; y < WorldExtents.Y; y++)
3222 {
3223 for (int x = 0; x < WorldExtents.X; x++)
3224 {
3225 resultarr2[y * 2, x * 2] = resultarr[y, x];
3226
3227 if (y < WorldExtents.Y)
3228 {
3229 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3230 }
3231 if (x < WorldExtents.X)
3232 {
3233 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3234 }
3235 if (x < WorldExtents.X && y < WorldExtents.Y)
3236 {
3237 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3238 }
3239 }
3240 }
3241
3242 //Flatten out the array
3243 int i = 0;
3244 for (int y = 0; y < 512; y++)
3245 {
3246 for (int x = 0; x < 512; x++)
3247 {
3248 if (resultarr2[y, x] <= 0)
3249 returnarr[i] = 0.0000001f;
3250 else
3251 returnarr[i] = resultarr2[y, x];
3252
3253 i++;
3254 }
3255 }
3256
3257 return returnarr;
3258 }
3259
3260 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3261 {
3262 float[] returnarr = new float[262144];
3263 float[,] resultarr = new float[512,512];
3264
3265 // Filling out the array into its multi-dimensional components
3266 for (int y = 0; y < 256; y++)
3267 {
3268 for (int x = 0; x < 256; x++)
3269 {
3270 resultarr[y, x] = heightMap[y * 256 + x];
3271 }
3272 }
3273
3274 // Resize using interpolation
3275
3276 // This particular way is quick but it only works on a multiple of the original
3277
3278 // The idea behind this method can be described with the following diagrams
3279 // second pass and third pass happen in the same loop really.. just separated
3280 // them to show what this does.
3281
3282 // First Pass
3283 // ResultArr:
3284 // 1,1,1,1,1,1
3285 // 1,1,1,1,1,1
3286 // 1,1,1,1,1,1
3287 // 1,1,1,1,1,1
3288 // 1,1,1,1,1,1
3289 // 1,1,1,1,1,1
3290
3291 // Second Pass
3292 // ResultArr2:
3293 // 1,,1,,1,,1,,1,,1,
3294 // ,,,,,,,,,,
3295 // 1,,1,,1,,1,,1,,1,
3296 // ,,,,,,,,,,
3297 // 1,,1,,1,,1,,1,,1,
3298 // ,,,,,,,,,,
3299 // 1,,1,,1,,1,,1,,1,
3300 // ,,,,,,,,,,
3301 // 1,,1,,1,,1,,1,,1,
3302 // ,,,,,,,,,,
3303 // 1,,1,,1,,1,,1,,1,
3304
3305 // Third pass fills in the blanks
3306 // ResultArr2:
3307 // 1,1,1,1,1,1,1,1,1,1,1,1
3308 // 1,1,1,1,1,1,1,1,1,1,1,1
3309 // 1,1,1,1,1,1,1,1,1,1,1,1
3310 // 1,1,1,1,1,1,1,1,1,1,1,1
3311 // 1,1,1,1,1,1,1,1,1,1,1,1
3312 // 1,1,1,1,1,1,1,1,1,1,1,1
3313 // 1,1,1,1,1,1,1,1,1,1,1,1
3314 // 1,1,1,1,1,1,1,1,1,1,1,1
3315 // 1,1,1,1,1,1,1,1,1,1,1,1
3316 // 1,1,1,1,1,1,1,1,1,1,1,1
3317 // 1,1,1,1,1,1,1,1,1,1,1,1
3318
3319 // X,Y = .
3320 // X+1,y = ^
3321 // X,Y+1 = *
3322 // X+1,Y+1 = #
3323
3324 // Filling in like this;
3325 // .*
3326 // ^#
3327 // 1st .
3328 // 2nd *
3329 // 3rd ^
3330 // 4th #
3331 // on single loop.
3332
3333 float[,] resultarr2 = new float[512,512];
3334 for (int y = 0; y < (int)Constants.RegionSize; y++)
3335 {
3336 for (int x = 0; x < (int)Constants.RegionSize; x++)
3337 {
3338 resultarr2[y*2, x*2] = resultarr[y, x];
3339
3340 if (y < (int)Constants.RegionSize)
3341 {
3342 if (y + 1 < (int)Constants.RegionSize)
3343 {
3344 if (x + 1 < (int)Constants.RegionSize)
3345 {
3346 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3347 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3348 }
3349 else
3350 {
3351 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3352 }
3353 }
3354 else
3355 {
3356 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3357 }
3358 }
3359 if (x < (int)Constants.RegionSize)
3360 {
3361 if (x + 1 < (int)Constants.RegionSize)
3362 {
3363 if (y + 1 < (int)Constants.RegionSize)
3364 {
3365 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3366 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3367 }
3368 else
3369 {
3370 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3371 }
3372 }
3373 else
3374 {
3375 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3376 }
3377 }
3378 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3379 {
3380 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3381 {
3382 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3383 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3384 }
3385 else
3386 {
3387 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3388 }
3389 }
3390 }
3391 }
3392 //Flatten out the array
3393 int i = 0;
3394 for (int y = 0; y < 512; y++)
3395 {
3396 for (int x = 0; x < 512; x++)
3397 {
3398 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3399 {
3400 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3401 resultarr2[y, x] = 0;
3402 }
3403 returnarr[i] = resultarr2[y, x];
3404 i++;
3405 }
3406 }
3407
3408 return returnarr;
3409 }
3410
3411 #endregion
3412
3413 public override void SetTerrain(float[] heightMap)
3414 {
3415 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3416 {
3417 if (m_parentScene is OdeScene)
3418 {
3419 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3420 }
3421 }
3422 else
3423 {
3424 SetTerrain(heightMap, m_worldOffset);
3425 }
3426 }
3427
3428 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3429 {
3430
3431 uint regionsize = (uint) Constants.RegionSize; // visible region size eg. 256(M)
3432
3433 uint heightmapWidth = regionsize + 1; // ODE map size 257 x 257 (Meters) (1 extra
3434 uint heightmapHeight = regionsize + 1;
3435
3436 uint heightmapWidthSamples = (uint)regionsize + 2; // Sample file size, 258 x 258 samples
3437 uint heightmapHeightSamples = (uint)regionsize + 2;
3438
3439 // Array of height samples for ODE
3440 float[] _heightmap;
3441 _heightmap = new float[(heightmapWidthSamples * heightmapHeightSamples)]; // loaded samples 258 x 258
3442
3443 // Other ODE parameters
3444 const float scale = 1.0f;
3445 const float offset = 0.0f;
3446 const float thickness = 2.0f; // Was 0.2f, Larger appears to prevent Av fall-through
3447 const int wrap = 0;
3448
3449 float hfmin = 2000f;
3450 float hfmax = -2000f;
3451 float minele = 0.0f; // Dont allow -ve heights
3452
3453 uint x = 0;
3454 uint y = 0;
3455 uint xx = 0;
3456 uint yy = 0;
3457
3458 // load the height samples array from the heightMap
3459 for ( x = 0; x < heightmapWidthSamples; x++) // 0 to 257
3460 {
3461 for ( y = 0; y < heightmapHeightSamples; y++) // 0 to 257
3462 {
3463 xx = x - 1;
3464 if (xx < 0) xx = 0;
3465 if (xx > (regionsize - 1)) xx = regionsize - 1;
3466
3467 yy = y - 1;
3468 if (yy < 0) yy = 0;
3469 if (yy > (regionsize - 1)) yy = regionsize - 1;
3470 // Input xx = 0 0 1 2 ..... 254 255 255 256 total in
3471 // Output x = 0 1 2 3 ..... 255 256 257 258 total out
3472 float val= heightMap[(yy * regionsize) + xx]; // input from heightMap, <0-255 * 256> <0-255>
3473 if (val < minele) val = minele;
3474 _heightmap[x * (regionsize + 2) + y] = val; // samples output to _heightmap, <0-257 * 258> <0-257>
3475 hfmin = (val < hfmin) ? val : hfmin;
3476 hfmax = (val > hfmax) ? val : hfmax;
3477 }
3478 }
3479
3480 lock (OdeLock)
3481 {
3482 IntPtr GroundGeom = IntPtr.Zero;
3483 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3484 {
3485 RegionTerrain.Remove(pOffset);
3486 if (GroundGeom != IntPtr.Zero)
3487 {
3488 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3489 {
3490 TerrainHeightFieldHeights.Remove(GroundGeom);
3491 }
3492 d.SpaceRemove(space, GroundGeom);
3493 d.GeomDestroy(GroundGeom);
3494 }
3495 }
3496 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3497 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0,
3498 heightmapWidth, heightmapHeight, (int)heightmapWidthSamples,
3499 (int)heightmapHeightSamples, scale, offset, thickness, wrap);
3500 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3501 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3502 if (GroundGeom != IntPtr.Zero)
3503 {
3504 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3505 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3506 }
3507 geom_name_map[GroundGeom] = "Terrain";
3508
3509 d.Matrix3 R = new d.Matrix3();
3510
3511 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3512 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3513 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3514
3515 q1 = q1 * q2;
3516 //q1 = q1 * q3;
3517 Vector3 v3;
3518 float angle;
3519 q1.GetAxisAngle(out v3, out angle);
3520
3521 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3522 d.GeomSetRotation(GroundGeom, ref R);
3523 d.GeomSetPosition(GroundGeom, (pOffset.X + (regionsize * 0.5f)) - 0.5f, (pOffset.Y + (regionsize * 0.5f)) - 0.5f, 0);
3524 IntPtr testGround = IntPtr.Zero;
3525 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3526 {
3527 RegionTerrain.Remove(pOffset);
3528 }
3529 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3530 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3531 }
3532 }
3533
3534 public override void DeleteTerrain()
3535 {
3536 }
3537
3538 public float GetWaterLevel()
3539 {
3540 return waterlevel;
3541 }
3542
3543 public override bool SupportsCombining()
3544 {
3545 return true;
3546 }
3547
3548 public override void UnCombine(PhysicsScene pScene)
3549 {
3550 IntPtr localGround = IntPtr.Zero;
3551// float[] localHeightfield;
3552 bool proceed = false;
3553 List<IntPtr> geomDestroyList = new List<IntPtr>();
3554
3555 lock (OdeLock)
3556 {
3557 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3558 {
3559 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3560 {
3561 if (geom == localGround)
3562 {
3563// localHeightfield = TerrainHeightFieldHeights[geom];
3564 proceed = true;
3565 }
3566 else
3567 {
3568 geomDestroyList.Add(geom);
3569 }
3570 }
3571
3572 if (proceed)
3573 {
3574 m_worldOffset = Vector3.Zero;
3575 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3576 m_parentScene = null;
3577
3578 foreach (IntPtr g in geomDestroyList)
3579 {
3580 // removingHeightField needs to be done or the garbage collector will
3581 // collect the terrain data before we tell ODE to destroy it causing
3582 // memory corruption
3583 if (TerrainHeightFieldHeights.ContainsKey(g))
3584 {
3585// float[] removingHeightField = TerrainHeightFieldHeights[g];
3586 TerrainHeightFieldHeights.Remove(g);
3587
3588 if (RegionTerrain.ContainsKey(g))
3589 {
3590 RegionTerrain.Remove(g);
3591 }
3592
3593 d.GeomDestroy(g);
3594 //removingHeightField = new float[0];
3595 }
3596 }
3597
3598 }
3599 else
3600 {
3601 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3602
3603 }
3604 }
3605 }
3606 }
3607
3608 public override void SetWaterLevel(float baseheight)
3609 {
3610 waterlevel = baseheight;
3611 randomizeWater(waterlevel);
3612 }
3613
3614 public void randomizeWater(float baseheight)
3615 {
3616 const uint heightmapWidth = m_regionWidth + 2;
3617 const uint heightmapHeight = m_regionHeight + 2;
3618 const uint heightmapWidthSamples = m_regionWidth + 2;
3619 const uint heightmapHeightSamples = m_regionHeight + 2;
3620 const float scale = 1.0f;
3621 const float offset = 0.0f;
3622 const float thickness = 2.9f;
3623 const int wrap = 0;
3624
3625 for (int i = 0; i < (258 * 258); i++)
3626 {
3627 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3628 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3629 }
3630
3631 lock (OdeLock)
3632 {
3633 if (WaterGeom != IntPtr.Zero)
3634 {
3635 d.SpaceRemove(space, WaterGeom);
3636 }
3637 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3638 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3639 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3640 offset, thickness, wrap);
3641 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3642 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3643 if (WaterGeom != IntPtr.Zero)
3644 {
3645 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3646 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3647
3648 }
3649 geom_name_map[WaterGeom] = "Water";
3650
3651 d.Matrix3 R = new d.Matrix3();
3652
3653 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3654 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3655 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3656
3657 q1 = q1 * q2;
3658 //q1 = q1 * q3;
3659 Vector3 v3;
3660 float angle;
3661 q1.GetAxisAngle(out v3, out angle);
3662
3663 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3664 d.GeomSetRotation(WaterGeom, ref R);
3665 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3666
3667 }
3668
3669 }
3670
3671 public override void Dispose()
3672 {
3673 m_rayCastManager.Dispose();
3674 m_rayCastManager = null;
3675
3676 lock (OdeLock)
3677 {
3678 lock (_prims)
3679 {
3680 foreach (OdePrim prm in _prims)
3681 {
3682 RemovePrim(prm);
3683 }
3684 }
3685
3686 //foreach (OdeCharacter act in _characters)
3687 //{
3688 //RemoveAvatar(act);
3689 //}
3690 d.WorldDestroy(world);
3691 //d.CloseODE();
3692 }
3693 }
3694 public override Dictionary<uint, float> GetTopColliders()
3695 {
3696 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3697 int cnt = 0;
3698 lock (_prims)
3699 {
3700 foreach (OdePrim prm in _prims)
3701 {
3702 if (prm.CollisionScore > 0)
3703 {
3704 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3705 cnt++;
3706 prm.CollisionScore = 0f;
3707 if (cnt > 25)
3708 {
3709 break;
3710 }
3711 }
3712 }
3713 }
3714 return returncolliders;
3715 }
3716
3717 public override bool SupportsRayCast()
3718 {
3719 return true;
3720 }
3721
3722 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3723 {
3724 if (retMethod != null)
3725 {
3726 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3727 }
3728 }
3729
3730#if USE_DRAWSTUFF
3731 // Keyboard callback
3732 public void command(int cmd)
3733 {
3734 IntPtr geom;
3735 d.Mass mass;
3736 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3737
3738
3739
3740 Char ch = Char.ToLower((Char)cmd);
3741 switch ((Char)ch)
3742 {
3743 case 'w':
3744 try
3745 {
3746 Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3747
3748 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3749 ds.SetViewpoint(ref xyz, ref hpr);
3750 }
3751 catch (ArgumentException)
3752 { hpr.X = 0; }
3753 break;
3754
3755 case 'a':
3756 hpr.X++;
3757 ds.SetViewpoint(ref xyz, ref hpr);
3758 break;
3759
3760 case 's':
3761 try
3762 {
3763 Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3764
3765 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3766 ds.SetViewpoint(ref xyz, ref hpr);
3767 }
3768 catch (ArgumentException)
3769 { hpr.X = 0; }
3770 break;
3771 case 'd':
3772 hpr.X--;
3773 ds.SetViewpoint(ref xyz, ref hpr);
3774 break;
3775 case 'r':
3776 xyz.Z++;
3777 ds.SetViewpoint(ref xyz, ref hpr);
3778 break;
3779 case 'f':
3780 xyz.Z--;
3781 ds.SetViewpoint(ref xyz, ref hpr);
3782 break;
3783 case 'e':
3784 xyz.Y++;
3785 ds.SetViewpoint(ref xyz, ref hpr);
3786 break;
3787 case 'q':
3788 xyz.Y--;
3789 ds.SetViewpoint(ref xyz, ref hpr);
3790 break;
3791 }
3792 }
3793
3794 public void step(int pause)
3795 {
3796
3797 ds.SetColor(1.0f, 1.0f, 0.0f);
3798 ds.SetTexture(ds.Texture.Wood);
3799 lock (_prims)
3800 {
3801 foreach (OdePrim prm in _prims)
3802 {
3803 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3804 if (prm.prim_geom != IntPtr.Zero)
3805 {
3806 d.Vector3 pos;
3807 d.GeomCopyPosition(prm.prim_geom, out pos);
3808 //d.BodyCopyPosition(body, out pos);
3809
3810 d.Matrix3 R;
3811 d.GeomCopyRotation(prm.prim_geom, out R);
3812 //d.BodyCopyRotation(body, out R);
3813
3814
3815 d.Vector3 sides = new d.Vector3();
3816 sides.X = prm.Size.X;
3817 sides.Y = prm.Size.Y;
3818 sides.Z = prm.Size.Z;
3819
3820 ds.DrawBox(ref pos, ref R, ref sides);
3821 }
3822 }
3823 }
3824 ds.SetColor(1.0f, 0.0f, 0.0f);
3825 lock (_characters)
3826 {
3827 foreach (OdeCharacter chr in _characters)
3828 {
3829 if (chr.Shell != IntPtr.Zero)
3830 {
3831 IntPtr body = d.GeomGetBody(chr.Shell);
3832
3833 d.Vector3 pos;
3834 d.GeomCopyPosition(chr.Shell, out pos);
3835 //d.BodyCopyPosition(body, out pos);
3836
3837 d.Matrix3 R;
3838 d.GeomCopyRotation(chr.Shell, out R);
3839 //d.BodyCopyRotation(body, out R);
3840
3841 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3842 d.Vector3 sides = new d.Vector3();
3843 sides.X = 0.5f;
3844 sides.Y = 0.5f;
3845 sides.Z = 0.5f;
3846
3847 ds.DrawBox(ref pos, ref R, ref sides);
3848 }
3849 }
3850 }
3851 }
3852
3853 public void start(int unused)
3854 {
3855 ds.SetViewpoint(ref xyz, ref hpr);
3856 }
3857#endif
3858 }
3859}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs
new file mode 100644
index 0000000..69e2d03
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs
@@ -0,0 +1,122 @@
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
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using log4net;
35using System.Reflection;
36
37namespace OpenSim.Region.Physics.OdePlugin
38{
39 [TestFixture]
40 public class ODETestClass
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 private OdePlugin cbt;
45 private PhysicsScene ps;
46 private IMeshingPlugin imp;
47
48 [SetUp]
49 public void Initialize()
50 {
51 // Loading ODEPlugin
52 cbt = new OdePlugin();
53 // Loading Zero Mesher
54 imp = new ZeroMesherPlugin();
55 // Getting Physics Scene
56 ps = cbt.GetScene("test");
57 // Initializing Physics Scene.
58 ps.Initialise(imp.GetMesher(),null);
59 float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize];
60 for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++)
61 {
62 _heightmap[i] = 21f;
63 }
64 ps.SetTerrain(_heightmap);
65 }
66
67 [TearDown]
68 public void Terminate()
69 {
70 ps.DeleteTerrain();
71 ps.Dispose();
72
73 }
74
75 [Test]
76 public void CreateAndDropPhysicalCube()
77 {
78 PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox();
79 Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f);
80 Vector3 size = new Vector3(0.5f, 0.5f, 0.5f);
81 Quaternion rot = Quaternion.Identity;
82 PhysicsActor prim = ps.AddPrimShape("CoolShape", newcube, position, size, rot, true);
83 OdePrim oprim = (OdePrim)prim;
84 OdeScene pscene = (OdeScene) ps;
85
86 Assert.That(oprim.m_taintadd);
87
88 prim.LocalID = 5;
89
90 for (int i = 0; i < 58; i++)
91 {
92 ps.Simulate(0.133f);
93
94 Assert.That(oprim.prim_geom != (IntPtr)0);
95
96 Assert.That(oprim.m_targetSpace != (IntPtr)0);
97
98 //Assert.That(oprim.m_targetSpace == pscene.space);
99 m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space);
100
101 Assert.That(!oprim.m_taintadd);
102 m_log.Info("Prim Position (" + oprim.m_localID + "): " + prim.Position.ToString());
103
104 // Make sure we're above the ground
105 //Assert.That(prim.Position.Z > 20f);
106 //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore);
107
108 // Make sure we've got a Body
109 Assert.That(oprim.Body != (IntPtr)0);
110 //m_log.Info(
111 }
112
113 // Make sure we're not somewhere above the ground
114 Assert.That(prim.Position.Z < 21.5f);
115
116 ps.RemovePrim(prim);
117 Assert.That(oprim.m_taintremove);
118 ps.Simulate(0.133f);
119 Assert.That(oprim.Body == (IntPtr)0);
120 }
121 }
122}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs b/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs
new file mode 100644
index 0000000..87ca446
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs
@@ -0,0 +1,98 @@
1/*
2 * Copyright ODE
3 * Ode.NET - .NET bindings for ODE
4 * Jason Perkins (starkos@industriousone.com)
5 * Licensed under the New BSD
6 * Part of the OpenDynamicsEngine
7Open Dynamics Engine
8Copyright (c) 2001-2007, Russell L. Smith.
9All rights reserved.
10
11Redistribution and use in source and binary forms, with or without
12modification, are permitted provided that the following conditions
13are met:
14
15Redistributions of source code must retain the above copyright notice,
16this list of conditions and the following disclaimer.
17
18Redistributions in binary form must reproduce the above copyright notice,
19this list of conditions and the following disclaimer in the documentation
20and/or other materials provided with the distribution.
21
22Neither the names of ODE's copyright owner nor the names of its
23contributors may be used to endorse or promote products derived from
24this software without specific prior written permission.
25
26THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
32TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 *
39 */
40
41using System;
42using System.Runtime.InteropServices;
43using Ode.NET;
44
45namespace Drawstuff.NET
46{
47#if dDOUBLE
48 using dReal = System.Double;
49#else
50 using dReal = System.Single;
51#endif
52
53 public static class ds
54 {
55 public const int VERSION = 2;
56
57 public enum Texture
58 {
59 None,
60 Wood
61 }
62
63 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
64 public delegate void CallbackFunction(int arg);
65
66 [StructLayout(LayoutKind.Sequential)]
67 public struct Functions
68 {
69 public int version;
70 public CallbackFunction start;
71 public CallbackFunction step;
72 public CallbackFunction command;
73 public CallbackFunction stop;
74 public string path_to_textures;
75 }
76
77 [DllImport("drawstuff", EntryPoint = "dsDrawBox")]
78 public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides);
79
80 [DllImport("drawstuff", EntryPoint = "dsDrawCapsule")]
81 public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius);
82
83 [DllImport("drawstuff", EntryPoint = "dsDrawConvex")]
84 public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons);
85
86 [DllImport("drawstuff", EntryPoint = "dsSetColor")]
87 public static extern void SetColor(float red, float green, float blue);
88
89 [DllImport("drawstuff", EntryPoint = "dsSetTexture")]
90 public static extern void SetTexture(Texture texture);
91
92 [DllImport("drawstuff", EntryPoint = "dsSetViewpoint")]
93 public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr);
94
95 [DllImport("drawstuff", EntryPoint = "dsSimulationLoop")]
96 public static extern void SimulationLoop(int argc, string[] argv, int window_width, int window_height, ref Functions fn);
97 }
98}