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