aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs')
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs3846
1 files changed, 3846 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
new file mode 100644
index 0000000..88f9658
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
@@ -0,0 +1,3846 @@
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 float geomRegionFence = 0.0f;
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 ContactCopy; // local copy that can be modified
268 private d.Contact TerrainContact;
269 private d.Contact AvatarStaticprimContact; // was 'contact'
270 private d.Contact AvatarMovementprimContact;
271 private d.Contact AvatarMovementTerrainContact;
272 private d.Contact WaterContact;
273 private d.Contact[,] m_materialContacts;
274
275//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
276//Ckrinke private int m_randomizeWater = 200;
277 private int m_physicsiterations = 10;
278 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
279 private readonly PhysicsActor PANull = new NullPhysicsActor();
280 private float step_time = 0.0f;
281//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
282//Ckrinke private int ms = 0;
283 public IntPtr world;
284 //private bool returncollisions = false;
285 // private uint obj1LocalID = 0;
286 private uint obj2LocalID = 0;
287 //private int ctype = 0;
288 private OdeCharacter cc1;
289 private OdePrim cp1;
290 private OdeCharacter cc2;
291 private OdePrim cp2;
292 //private int cStartStop = 0;
293 //private string cDictKey = "";
294
295 public IntPtr space;
296
297 //private IntPtr tmpSpace;
298 // split static geometry collision handling into spaces of 30 meters
299 public IntPtr[,] staticPrimspace;
300
301 public Object OdeLock;
302
303 public IMesher mesher;
304
305 private IConfigSource m_config;
306
307 public bool physics_logging = false;
308 public int physics_logging_interval = 0;
309 public bool physics_logging_append_existing_logfile = false;
310
311 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
312 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
313
314 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
315 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
316 // TODO: unused: private uint heightmapWidthSamples;
317 // TODO: unused: private uint heightmapHeightSamples;
318
319 private volatile int m_global_contactcount = 0;
320
321 private Vector3 m_worldOffset = Vector3.Zero;
322 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
323 private PhysicsScene m_parentScene = null;
324
325 private ODERayCastRequestManager m_rayCastManager;
326
327 /// <summary>
328 /// Initiailizes the scene
329 /// Sets many properties that ODE requires to be stable
330 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
331 /// </summary>
332 public OdeScene(CollisionLocker dode, string sceneIdentifier)
333 {
334 m_log
335 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
336
337 OdeLock = new Object();
338 ode = dode;
339 nearCallback = near;
340 triCallback = TriCallback;
341 triArrayCallback = TriArrayCallback;
342 m_rayCastManager = new ODERayCastRequestManager(this);
343 lock (OdeLock)
344 {
345 // Create the world and the first space
346 world = d.WorldCreate();
347 space = d.HashSpaceCreate(IntPtr.Zero);
348
349
350 contactgroup = d.JointGroupCreate(0);
351 //contactgroup
352
353 d.WorldSetAutoDisableFlag(world, false);
354 #if USE_DRAWSTUFF
355
356 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
357 viewthread.Start();
358 #endif
359 }
360
361
362 _watermap = new float[258 * 258];
363
364 // Zero out the prim spaces array (we split our space into smaller spaces so
365 // we can hit test less.
366 }
367
368#if USE_DRAWSTUFF
369 public void startvisualization(object o)
370 {
371 ds.Functions fn;
372 fn.version = ds.VERSION;
373 fn.start = new ds.CallbackFunction(start);
374 fn.step = new ds.CallbackFunction(step);
375 fn.command = new ds.CallbackFunction(command);
376 fn.stop = null;
377 fn.path_to_textures = "./textures";
378 string[] args = new string[0];
379 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
380 }
381#endif
382
383 // Initialize the mesh plugin
384 public override void Initialise(IMesher meshmerizer, IConfigSource config)
385 {
386 mesher = meshmerizer;
387 m_config = config;
388 // Defaults
389
390 if (Environment.OSVersion.Platform == PlatformID.Unix)
391 {
392 avPIDD = 3200.0f;
393 avPIDP = 1400.0f;
394 avStandupTensor = 2000000f;
395 }
396 else
397 {
398 avPIDD = 2200.0f;
399 avPIDP = 900.0f;
400 avStandupTensor = 550000f;
401 }
402
403 int contactsPerCollision = 80;
404
405 if (m_config != null)
406 {
407 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
408 if (physicsconfig != null)
409 {
410 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
411 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
412 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
413
414 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
415 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
416
417 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
418 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
419 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
420
421 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
422
423 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
424 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
425 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
426
427 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
428 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
429 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
430
431 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
432 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
433
434 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
435 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
436
437 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
438 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
439
440 avDensity = physicsconfig.GetFloat("av_density", 80f);
441 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
442 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
443 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
444 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
445 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
446
447 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
448
449 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
450 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
451 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
452 geomRegionFence = physicsconfig.GetFloat("region_border_fence", 0.0f);
453
454 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
455 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
456
457 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
458 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
459
460 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
461 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
462 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
463 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
464 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
465
466 if (Environment.OSVersion.Platform == PlatformID.Unix)
467 {
468 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
469 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
470 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
471 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
472 }
473 else
474 {
475 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
476 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
477 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
478 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
479 }
480
481 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
482 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
483 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
484
485 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
486 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
487 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
488 }
489 }
490
491 contacts = new d.ContactGeom[contactsPerCollision];
492
493 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
494
495 // Avatar static on a Prim parameters
496 AvatarStaticprimContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
497 AvatarStaticprimContact.surface.mu = 255.0f;
498 AvatarStaticprimContact.surface.bounce = 0.0f;
499 AvatarStaticprimContact.surface.soft_cfm = 0.0f;
500 AvatarStaticprimContact.surface.soft_erp = 0.30f; // If this is too small static Av will fall through a sloping prim. 1.0 prevents fall-thru
501
502 // Avatar moving on a Prim parameters
503 AvatarMovementprimContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
504 AvatarMovementprimContact.surface.mu = 255.0f;
505 AvatarMovementprimContact.surface.bounce = 0.0f;
506 AvatarMovementprimContact.surface.soft_cfm = 0.0f; // if this is 0.01 then prims become phantom to Avs!
507 AvatarMovementprimContact.surface.soft_erp = 0.3f;
508
509 // Static Avatar on Terrain parameters
510 // Keeps Avatar in place better
511 TerrainContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
512 TerrainContact.surface.mu = 255.0f;
513 TerrainContact.surface.bounce = 0.0f;
514 TerrainContact.surface.soft_cfm = 0.0f;
515 TerrainContact.surface.soft_erp = 0.05f;
516
517 // Moving Avatar on Terrain parameters
518 AvatarMovementTerrainContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
519 AvatarMovementTerrainContact.surface.mu = 75f;
520 AvatarMovementTerrainContact.surface.bounce = 0.0f;
521 AvatarMovementTerrainContact.surface.soft_cfm = 0.0f;
522 AvatarMovementTerrainContact.surface.soft_erp = 0.05f;
523
524 // Avatar or prim the the water, this may not be used, possibly water is same as air?
525 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
526 WaterContact.surface.mu = 0.0f; // No friction
527 WaterContact.surface.bounce = 0.0f; // No bounce
528 WaterContact.surface.soft_cfm = 0.010f;
529 WaterContact.surface.soft_erp = 0.010f;
530
531
532 // Prim static or moving on a prim, depends on material type
533 m_materialContacts = new d.Contact[7,2];
534 // V 1 = Sliding; 0 = static or fell onto
535 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
536 m_materialContacts[(int)Material.Stone, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
537 m_materialContacts[(int)Material.Stone, 0].surface.mu = 60f; // friction, 1 = slippery, 255 = no slip
538 m_materialContacts[(int)Material.Stone, 0].surface.bounce = 0.0f;
539 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.0f;
540 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.50f; // erp also changes friction, more erp=less friction
541
542 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
543 m_materialContacts[(int)Material.Stone, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
544 m_materialContacts[(int)Material.Stone, 1].surface.mu = 40f;
545 m_materialContacts[(int)Material.Stone, 1].surface.bounce = 0.0f;
546 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.0f;
547 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.50f;
548
549 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
550 m_materialContacts[(int)Material.Metal, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
551 m_materialContacts[(int)Material.Metal, 0].surface.mu = 15f;
552 m_materialContacts[(int)Material.Metal, 0].surface.bounce = 0.2f;
553 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.0f;
554 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.50f;
555
556 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
557 m_materialContacts[(int)Material.Metal, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
558 m_materialContacts[(int)Material.Metal, 1].surface.mu = 10f;
559 m_materialContacts[(int)Material.Metal, 1].surface.bounce = 0.2f;
560 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.0f;
561 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.50f;
562
563 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
564 m_materialContacts[(int)Material.Glass, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
565 m_materialContacts[(int)Material.Glass, 0].surface.mu = 7.5f;
566 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.0f;
567 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.0f;
568 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.50f;
569
570 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
571 m_materialContacts[(int)Material.Glass, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
572 m_materialContacts[(int)Material.Glass, 1].surface.mu = 5f;
573 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.0f;
574 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.0f;
575 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.50f;
576
577 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
578 m_materialContacts[(int)Material.Wood, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
579 m_materialContacts[(int)Material.Wood, 0].surface.mu = 45f;
580 m_materialContacts[(int)Material.Wood, 0].surface.bounce = 0.1f;
581 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.0f;
582 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.50f;
583
584 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
585 m_materialContacts[(int)Material.Wood, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
586 m_materialContacts[(int)Material.Wood, 1].surface.mu = 30f;
587 m_materialContacts[(int)Material.Wood, 1].surface.bounce = 0.1f;
588 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.0f;
589 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.50f;
590
591 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
592 m_materialContacts[(int)Material.Flesh, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
593 m_materialContacts[(int)Material.Flesh, 0].surface.mu = 150f;
594 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = 0.0f;
595 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.0f;
596 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.50f;
597
598 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
599 m_materialContacts[(int)Material.Flesh, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
600 m_materialContacts[(int)Material.Flesh, 1].surface.mu = 100f;
601 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = 0.0f;
602 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.0f;
603 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.50f;
604
605 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
606 m_materialContacts[(int)Material.Plastic, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
607 m_materialContacts[(int)Material.Plastic, 0].surface.mu = 30f;
608 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = 0.2f;
609 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.0f;
610 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.50f;
611
612 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
613 m_materialContacts[(int)Material.Plastic, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
614 m_materialContacts[(int)Material.Plastic, 1].surface.mu = 20f;
615 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = 0.2f;
616 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.0f;
617 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.50f;
618
619 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
620 m_materialContacts[(int)Material.Rubber, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
621 m_materialContacts[(int)Material.Rubber, 0].surface.mu = 150f;
622 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = 0.7f;
623 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.0f;
624 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.50f;
625
626 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
627 m_materialContacts[(int)Material.Rubber, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
628 m_materialContacts[(int)Material.Rubber, 1].surface.mu = 100f;
629 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = 0.7f;
630 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.0f;
631 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.50f;
632
633 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
634
635 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
636
637 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
638 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
639
640
641 d.WorldSetLinearDampingThreshold(world, 256f);
642 d.WorldSetLinearDamping(world, 256f);
643// d.WorldSetLinearDampingThreshold(world, 0.01f);
644// d.WorldSetLinearDamping(world, 0.1f);
645 d.WorldSetAngularDampingThreshold(world, 256f);
646 d.WorldSetAngularDamping(world, 256f);
647 d.WorldSetMaxAngularSpeed(world, 256f);
648
649 // Set how many steps we go without running collision testing
650 // This is in addition to the step size.
651 // Essentially Steps * m_physicsiterations
652 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
653 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
654
655
656
657 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
658 {
659 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
660 {
661 staticPrimspace[i, j] = IntPtr.Zero;
662 }
663 }
664 }
665
666 internal void waitForSpaceUnlock(IntPtr space)
667 {
668 //if (space != IntPtr.Zero)
669 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
670 }
671
672 /// <summary>
673 /// Debug space message for printing the space that a prim/avatar is in.
674 /// </summary>
675 /// <param name="pos"></param>
676 /// <returns>Returns which split up space the given position is in.</returns>
677 public string whichspaceamIin(Vector3 pos)
678 {
679 return calculateSpaceForGeom(pos).ToString();
680 }
681
682 #region Collision Detection
683
684 /// <summary>
685 /// This is our near callback. A geometry is near a body
686 /// </summary>
687 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
688 /// <param name="g1">a geometry or space</param>
689 /// <param name="g2">another geometry or space</param>
690 private void near(IntPtr space, IntPtr g1, IntPtr g2)
691 {
692 // no lock here! It's invoked from within Simulate(), which is thread-locked
693
694 // Test if we're colliding a geom with a space.
695 // If so we have to drill down into the space recursively
696//Console.WriteLine("near -----------"); //##
697 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
698 {
699 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
700 return;
701
702 // Separating static prim geometry spaces.
703 // We'll be calling near recursivly if one
704 // of them is a space to find all of the
705 // contact points in the space
706 try
707 {
708 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
709 }
710 catch (AccessViolationException)
711 {
712 m_log.Warn("[PHYSICS]: Unable to collide test a space");
713 return;
714 }
715 //Colliding a space or a geom with a space or a geom. so drill down
716
717 //Collide all geoms in each space..
718 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
719 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
720 return;
721 }
722
723 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
724 return;
725
726 IntPtr b1 = d.GeomGetBody(g1);
727 IntPtr b2 = d.GeomGetBody(g2);
728
729 // d.GeomClassID id = d.GeomGetClass(g1);
730
731 String name1 = null;
732 String name2 = null;
733
734 if (!geom_name_map.TryGetValue(g1, out name1))
735 {
736 name1 = "null";
737 }
738 if (!geom_name_map.TryGetValue(g2, out name2))
739 {
740 name2 = "null";
741 }
742
743 //if (id == d.GeomClassId.TriMeshClass)
744 //{
745 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
746 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
747 //}
748
749 // Figure out how many contact points we have
750 int count = 0;
751 try
752 {
753 // Colliding Geom To Geom
754 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
755
756 if (g1 == g2)
757 return; // Can't collide with yourself
758
759 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
760 return;
761
762 lock (contacts)
763 {
764 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
765 if (count > contacts.Length)
766 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
767 }
768 }
769 catch (SEHException)
770 {
771 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.");
772 ode.drelease(world);
773 base.TriggerPhysicsBasedRestart();
774 }
775 catch (Exception e)
776 {
777 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
778 return;
779 }
780
781 PhysicsActor p1;
782 PhysicsActor p2;
783
784 if (!actor_name_map.TryGetValue(g1, out p1))
785 {
786 p1 = PANull;
787 }
788
789 if (!actor_name_map.TryGetValue(g2, out p2))
790 {
791 p2 = PANull;
792 }
793
794 ContactPoint maxDepthContact = new ContactPoint();
795 if (p1.CollisionScore + count >= float.MaxValue)
796 p1.CollisionScore = 0;
797 p1.CollisionScore += count;
798
799 if (p2.CollisionScore + count >= float.MaxValue)
800 p2.CollisionScore = 0;
801 p2.CollisionScore += count;
802 for (int i = 0; i < count; i++)
803 {
804 d.ContactGeom curContact = contacts[i];
805
806 if (curContact.depth > maxDepthContact.PenetrationDepth)
807 {
808 maxDepthContact = new ContactPoint(
809 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
810 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
811 curContact.depth
812 );
813 }
814
815 //m_log.Warn("[CCOUNT]: " + count);
816 IntPtr joint;
817 // If we're colliding with terrain, use 'TerrainContact' instead of AvatarStaticprimContact.
818 // allows us to have different settings
819
820 // We only need to test p2 for 'jump crouch purposes'
821 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
822 {
823 // Testing if the collision is at the feet of the avatar
824
825 //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));
826//#@ if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
827//#@ p2.IsColliding = true;
828 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)){ //##
829 p2.IsColliding = true; //##
830 }else{
831
832 } //##
833 }
834 else
835 {
836 p2.IsColliding = true;
837 }
838
839 //if ((framecount % m_returncollisions) == 0)
840
841 switch (p1.PhysicsActorType)
842 {
843 case (int)ActorTypes.Agent:
844 p2.CollidingObj = true;
845 break;
846 case (int)ActorTypes.Prim:
847 if (p2.Velocity.LengthSquared() > 0.0f)
848 p2.CollidingObj = true;
849 break;
850 case (int)ActorTypes.Unknown:
851 p2.CollidingGround = true;
852 break;
853 default:
854 p2.CollidingGround = true;
855 break;
856 }
857
858 // we don't want prim or avatar to explode
859
860 #region InterPenetration Handling - Unintended physics explosions
861# region disabled code1
862
863 if (curContact.depth >= 0.08f)
864 {
865 //This is disabled at the moment only because it needs more tweaking
866 //It will eventually be uncommented
867 /*
868 if (AvatarStaticprimContact.depth >= 1.00f)
869 {
870 //m_log.Debug("[PHYSICS]: " + AvatarStaticprimContact.depth.ToString());
871 }
872
873 //If you interpenetrate a prim with an agent
874 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
875 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
876 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
877 p2.PhysicsActorType == (int) ActorTypes.Prim))
878 {
879
880 //AvatarStaticprimContact.depth = AvatarStaticprimContact.depth * 4.15f;
881 /*
882 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
883 {
884 p2.CollidingObj = true;
885 AvatarStaticprimContact.depth = 0.003f;
886 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
887 OdeCharacter character = (OdeCharacter) p2;
888 character.SetPidStatus(true);
889 AvatarStaticprimContact.pos = new d.Vector3(AvatarStaticprimContact.pos.X + (p1.Size.X / 2), AvatarStaticprimContact.pos.Y + (p1.Size.Y / 2), AvatarStaticprimContact.pos.Z + (p1.Size.Z / 2));
890
891 }
892 else
893 {
894
895 //AvatarStaticprimContact.depth = 0.0000000f;
896 }
897 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
898 {
899
900 p1.CollidingObj = true;
901 AvatarStaticprimContact.depth = 0.003f;
902 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
903 AvatarStaticprimContact.pos = new d.Vector3(AvatarStaticprimContact.pos.X + (p2.Size.X / 2), AvatarStaticprimContact.pos.Y + (p2.Size.Y / 2), AvatarStaticprimContact.pos.Z + (p2.Size.Z / 2));
904 OdeCharacter character = (OdeCharacter)p1;
905 character.SetPidStatus(true);
906 }
907 else
908 {
909
910 //AvatarStaticprimContact.depth = 0.0000000f;
911 }
912
913
914
915 }
916*/
917 // If you interpenetrate a prim with another prim
918 /*
919 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
920 {
921 #region disabledcode2
922 //OdePrim op1 = (OdePrim)p1;
923 //OdePrim op2 = (OdePrim)p2;
924 //op1.m_collisionscore++;
925 //op2.m_collisionscore++;
926
927 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
928 //{
929 //op1.m_taintdisable = true;
930 //AddPhysicsActorTaint(p1);
931 //op2.m_taintdisable = true;
932 //AddPhysicsActorTaint(p2);
933 //}
934
935 //if (AvatarStaticprimContact.depth >= 0.25f)
936 //{
937 // Don't collide, one or both prim will expld.
938
939 //op1.m_interpenetrationcount++;
940 //op2.m_interpenetrationcount++;
941 //interpenetrations_before_disable = 200;
942 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
943 //{
944 //op1.m_taintdisable = true;
945 //AddPhysicsActorTaint(p1);
946 //}
947 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
948 //{
949 // op2.m_taintdisable = true;
950 //AddPhysicsActorTaint(p2);
951 //}
952
953 //AvatarStaticprimContact.depth = AvatarStaticprimContact.depth / 8f;
954 //AvatarStaticprimContact.normal = new d.Vector3(0, 0, 1);
955 //}
956 //if (op1.m_disabled || op2.m_disabled)
957 //{
958 //Manually disabled objects stay disabled
959 //AvatarStaticprimContact.depth = 0f;
960 //}
961 #endregion
962 }
963 */
964#endregion
965 if (curContact.depth >= 1.00f)
966 {
967 //m_log.Info("[P]: " + AvatarStaticprimContact.depth.ToString());
968 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
969 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
970 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
971 p2.PhysicsActorType == (int) ActorTypes.Unknown))
972 {
973 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
974 {
975 if (p2 is OdeCharacter)
976 {
977 OdeCharacter character = (OdeCharacter) p2;
978
979 //p2.CollidingObj = true;
980 curContact.depth = 0.00000003f;
981 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
982 curContact.pos =
983 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
984 curContact.pos.Y + (p1.Size.Y/2),
985 curContact.pos.Z + (p1.Size.Z/2));
986 character.SetPidStatus(true);
987 }
988 }
989
990
991 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
992 {
993 if (p1 is OdeCharacter)
994 {
995 OdeCharacter character = (OdeCharacter) p1;
996
997 //p2.CollidingObj = true;
998 curContact.depth = 0.00000003f;
999 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1000 curContact.pos =
1001 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1002 curContact.pos.Y + (p1.Size.Y/2),
1003 curContact.pos.Z + (p1.Size.Z/2));
1004 character.SetPidStatus(true);
1005 }
1006 }
1007 }
1008 }
1009 }
1010
1011 #endregion
1012
1013 // Logic for collision handling
1014 // Note, that if *all* contacts are skipped (VolumeDetect)
1015 // The prim still detects (and forwards) collision events but
1016 // appears to be phantom for the world
1017 Boolean skipThisContact = false;
1018
1019 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1020 skipThisContact = true; // No collision on volume detect prims
1021
1022 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1023 skipThisContact = true; // No collision on volume detect prims
1024
1025 if (!skipThisContact && curContact.depth < 0f)
1026 skipThisContact = true;
1027
1028 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1029 skipThisContact = true;
1030
1031 const int maxContactsbeforedeath = 4000;
1032 joint = IntPtr.Zero;
1033
1034 if (!skipThisContact)
1035 {
1036 // Add contact joints with materials params----------------------------------
1037 // p1 is what is being hit, p2 is the physical object doing the hitting
1038 int material = (int) Material.Wood;
1039 int movintYN = 0; // 1 = Sliding; 0 = static or fell onto
1040 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) movintYN = 1;
1041
1042 // If we're colliding against terrain
1043 if (name1 == "Terrain" || name2 == "Terrain")
1044 {
1045 // If we're moving
1046 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && (movintYN == 1))
1047 {
1048 //$ Av walk/run on terrain (not falling) Use the Avatar movement terrain contact
1049 AvatarMovementTerrainContact.geom = curContact;
1050 _perloopContact.Add(curContact);
1051 if (m_global_contactcount < maxContactsbeforedeath)
1052 {
1053 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1054 m_global_contactcount++;
1055 }
1056 }
1057 else
1058 {
1059 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1060 {
1061 //$ Av standing on terrain, Use the non moving Avata terrain contact
1062 TerrainContact.geom = curContact;
1063 _perloopContact.Add(curContact);
1064 if (m_global_contactcount < maxContactsbeforedeath)
1065 {
1066 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1067 m_global_contactcount++;
1068 }
1069 }
1070 else
1071 {
1072 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1073 {
1074 //& THIS NEVER HAPPENS? prim prim contact In terrain contact?
1075 // int pj294950 = 0;
1076 // prim terrain contact
1077
1078 if (p2 is OdePrim)
1079 material = ((OdePrim)p2).m_material;
1080 //m_log.DebugFormat("Material: {0}", material);
1081 m_materialContacts[material, movintYN].geom = curContact;
1082 _perloopContact.Add(curContact);
1083
1084 if (m_global_contactcount < maxContactsbeforedeath)
1085 {
1086 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1087 m_global_contactcount++;
1088
1089 }
1090
1091 }
1092 else
1093 {
1094 //$ prim on terrain contact
1095 if (p2 is OdePrim)
1096 material = ((OdePrim)p2).m_material;
1097 //m_log.DebugFormat("Material: {0}", material);
1098 m_materialContacts[material, movintYN].geom = curContact;
1099 _perloopContact.Add(curContact);
1100
1101 ContactCopy = m_materialContacts[material, movintYN];
1102 if(movintYN == 1)
1103 {
1104 // prevent excessive slide on terrain
1105 ContactCopy.surface.mu = m_materialContacts[material, movintYN].surface.mu * 30.0f;
1106 }
1107
1108 if (m_global_contactcount < maxContactsbeforedeath)
1109 {
1110 joint = d.JointCreateContact(world, contactgroup, ref ContactCopy);
1111 m_global_contactcount++;
1112 }
1113 }
1114 }
1115 }
1116 }
1117 else if (name1 == "Water" || name2 == "Water")
1118 {
1119 //$ This never happens! Perhaps water is treated like air?
1120 /*
1121 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1122 {
1123 }
1124 else
1125 {
1126 }
1127 */
1128 //WaterContact.surface.soft_cfm = 0.0000f;
1129 //WaterContact.surface.soft_erp = 0.00000f;
1130 if (curContact.depth > 0.1f)
1131 {
1132 curContact.depth *= 52;
1133 //AvatarStaticprimContact.normal = new d.Vector3(0, 0, 1);
1134 //AvatarStaticprimContact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1135 }
1136 WaterContact.geom = curContact;
1137 _perloopContact.Add(curContact);
1138 if (m_global_contactcount < maxContactsbeforedeath)
1139 {
1140 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1141 m_global_contactcount++;
1142 }
1143 //m_log.Info("[PHYSICS]: Prim Water Contact" + AvatarStaticprimContact.depth);
1144 }
1145 else
1146 {
1147
1148 // no terrain and no water, we're colliding with prim or avatar
1149 // check if we're moving
1150 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1151 {
1152 //$ Avatar on Prim or other Avatar
1153 if (movintYN == 1)
1154 {
1155 // Use the AV Movement / prim contact
1156 AvatarMovementprimContact.geom = curContact;
1157 _perloopContact.Add(curContact);
1158 if (m_global_contactcount < maxContactsbeforedeath)
1159 {
1160 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1161 m_global_contactcount++;
1162 }
1163 }
1164 else
1165 {
1166 // Use the Av non movement / prim contact
1167 AvatarStaticprimContact.geom = curContact;
1168 _perloopContact.Add(curContact);
1169 ContactCopy = AvatarStaticprimContact; // local copy so we can change locally
1170
1171 if (m_global_contactcount < maxContactsbeforedeath)
1172 {
1173 if (curContact.depth > 0.2)
1174 { // embedded, eject slowly
1175 ContactCopy.surface.soft_erp = 0.1f;
1176 ContactCopy.surface.soft_cfm = 0.1f;
1177 }
1178 else
1179 { // keep on the surface
1180 ContactCopy.surface.soft_erp = 0.3f;
1181 ContactCopy.surface.soft_cfm = 0.0f;
1182 }
1183 joint = d.JointCreateContact(world, contactgroup, ref ContactCopy);
1184 m_global_contactcount++;
1185 }
1186 }
1187 }
1188 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1189 {
1190 //$ Prim on Prim
1191 //p1.PhysicsActorType
1192
1193 if (p2 is OdePrim) material = ((OdePrim)p2).m_material;
1194 //m_log.DebugFormat("Material: {0}", material);
1195
1196 m_materialContacts[material, movintYN].geom = curContact;
1197 _perloopContact.Add(curContact);
1198
1199 if (m_global_contactcount < maxContactsbeforedeath)
1200 {
1201 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1202 m_global_contactcount++;
1203 }
1204 }
1205 }
1206
1207 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1208 {
1209 d.JointAttach(joint, b1, b2);
1210 m_global_contactcount++;
1211 }
1212
1213 }
1214 collision_accounting_events(p1, p2, maxDepthContact);
1215 if (count > geomContactPointsStartthrottle)
1216 {
1217 // If there are more then 3 contact points, it's likely
1218 // that we've got a pile of objects, so ...
1219 // We don't want to send out hundreds of terse updates over and over again
1220 // so lets throttle them and send them again after it's somewhat sorted out.
1221 p2.ThrottleUpdates = true;
1222 }
1223 //m_log.Debug(count.ToString());
1224 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1225 } // end for i.. loop
1226 } // end near
1227
1228 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1229 {
1230 bool result = false;
1231 //return result;
1232 if (!m_filterCollisions)
1233 return false;
1234
1235 ActorTypes at = (ActorTypes)atype;
1236 lock (_perloopContact)
1237 {
1238 foreach (d.ContactGeom contact in _perloopContact)
1239 {
1240 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1241 //{
1242 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1243 if (at == ActorTypes.Agent)
1244 {
1245 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)
1246 {
1247
1248 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1249 {
1250 //contactGeom.depth *= .00005f;
1251 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1252 // 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));
1253 result = true;
1254 break;
1255 }
1256 else
1257 {
1258 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1259 }
1260 }
1261 else
1262 {
1263 //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));
1264 //int i = 0;
1265 }
1266 }
1267 else if (at == ActorTypes.Prim)
1268 {
1269 //d.AABB aabb1 = new d.AABB();
1270 //d.AABB aabb2 = new d.AABB();
1271
1272 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1273 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1274 //aabb1.
1275 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)
1276 {
1277 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1278 {
1279 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1280 {
1281 result = true;
1282 break;
1283 }
1284 }
1285 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
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 }
1288
1289 }
1290
1291 //}
1292
1293 }
1294 }
1295 return result;
1296 }
1297
1298 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1299 {
1300 // obj1LocalID = 0;
1301 //returncollisions = false;
1302 obj2LocalID = 0;
1303 //ctype = 0;
1304 //cStartStop = 0;
1305 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1306 return;
1307
1308 switch ((ActorTypes)p2.PhysicsActorType)
1309 {
1310 case ActorTypes.Agent:
1311 cc2 = (OdeCharacter)p2;
1312
1313 // obj1LocalID = cc2.m_localID;
1314 switch ((ActorTypes)p1.PhysicsActorType)
1315 {
1316 case ActorTypes.Agent:
1317 cc1 = (OdeCharacter)p1;
1318 obj2LocalID = cc1.m_localID;
1319 cc1.AddCollisionEvent(cc2.m_localID, contact);
1320 //ctype = (int)CollisionCategories.Character;
1321
1322 //if (cc1.CollidingObj)
1323 //cStartStop = (int)StatusIndicators.Generic;
1324 //else
1325 //cStartStop = (int)StatusIndicators.Start;
1326
1327 //returncollisions = true;
1328 break;
1329 case ActorTypes.Prim:
1330 if (p1 is OdePrim)
1331 {
1332 cp1 = (OdePrim) p1;
1333 obj2LocalID = cp1.m_localID;
1334 cp1.AddCollisionEvent(cc2.m_localID, contact);
1335 }
1336 //ctype = (int)CollisionCategories.Geom;
1337
1338 //if (cp1.CollidingObj)
1339 //cStartStop = (int)StatusIndicators.Generic;
1340 //else
1341 //cStartStop = (int)StatusIndicators.Start;
1342
1343 //returncollisions = true;
1344 break;
1345
1346 case ActorTypes.Ground:
1347 case ActorTypes.Unknown:
1348 obj2LocalID = 0;
1349 //ctype = (int)CollisionCategories.Land;
1350 //returncollisions = true;
1351 break;
1352 }
1353
1354 cc2.AddCollisionEvent(obj2LocalID, contact);
1355 break;
1356 case ActorTypes.Prim:
1357
1358 if (p2 is OdePrim)
1359 {
1360 cp2 = (OdePrim) p2;
1361
1362 // obj1LocalID = cp2.m_localID;
1363 switch ((ActorTypes) p1.PhysicsActorType)
1364 {
1365 case ActorTypes.Agent:
1366 if (p1 is OdeCharacter)
1367 {
1368 cc1 = (OdeCharacter) p1;
1369 obj2LocalID = cc1.m_localID;
1370 cc1.AddCollisionEvent(cp2.m_localID, contact);
1371 //ctype = (int)CollisionCategories.Character;
1372
1373 //if (cc1.CollidingObj)
1374 //cStartStop = (int)StatusIndicators.Generic;
1375 //else
1376 //cStartStop = (int)StatusIndicators.Start;
1377 //returncollisions = true;
1378 }
1379 break;
1380 case ActorTypes.Prim:
1381
1382 if (p1 is OdePrim)
1383 {
1384 cp1 = (OdePrim) p1;
1385 obj2LocalID = cp1.m_localID;
1386 cp1.AddCollisionEvent(cp2.m_localID, contact);
1387 //ctype = (int)CollisionCategories.Geom;
1388
1389 //if (cp1.CollidingObj)
1390 //cStartStop = (int)StatusIndicators.Generic;
1391 //else
1392 //cStartStop = (int)StatusIndicators.Start;
1393
1394 //returncollisions = true;
1395 }
1396 break;
1397
1398 case ActorTypes.Ground:
1399 case ActorTypes.Unknown:
1400 obj2LocalID = 0;
1401 //ctype = (int)CollisionCategories.Land;
1402
1403 //returncollisions = true;
1404 break;
1405 }
1406
1407 cp2.AddCollisionEvent(obj2LocalID, contact);
1408 }
1409 break;
1410 }
1411 //if (returncollisions)
1412 //{
1413
1414 //lock (m_storedCollisions)
1415 //{
1416 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1417 //if (m_storedCollisions.ContainsKey(cDictKey))
1418 //{
1419 //sCollisionData objd = m_storedCollisions[cDictKey];
1420 //objd.NumberOfCollisions += 1;
1421 //objd.lastframe = framecount;
1422 //m_storedCollisions[cDictKey] = objd;
1423 //}
1424 //else
1425 //{
1426 //sCollisionData objd = new sCollisionData();
1427 //objd.ColliderLocalId = obj1LocalID;
1428 //objd.CollidedWithLocalId = obj2LocalID;
1429 //objd.CollisionType = ctype;
1430 //objd.NumberOfCollisions = 1;
1431 //objd.lastframe = framecount;
1432 //objd.StatusIndicator = cStartStop;
1433 //m_storedCollisions.Add(cDictKey, objd);
1434 //}
1435 //}
1436 // }
1437 }
1438
1439 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1440 {
1441 /* String name1 = null;
1442 String name2 = null;
1443
1444 if (!geom_name_map.TryGetValue(trimesh, out name1))
1445 {
1446 name1 = "null";
1447 }
1448 if (!geom_name_map.TryGetValue(refObject, out name2))
1449 {
1450 name2 = "null";
1451 }
1452
1453 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1454 */
1455 return 1;
1456 }
1457
1458 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1459 {
1460 String name1 = null;
1461 String name2 = null;
1462
1463 if (!geom_name_map.TryGetValue(trimesh, out name1))
1464 {
1465 name1 = "null";
1466 }
1467
1468 if (!geom_name_map.TryGetValue(refObject, out name2))
1469 {
1470 name2 = "null";
1471 }
1472
1473 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1474
1475 d.Vector3 v0 = new d.Vector3();
1476 d.Vector3 v1 = new d.Vector3();
1477 d.Vector3 v2 = new d.Vector3();
1478
1479 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1480 // 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);
1481
1482 return 1;
1483 }
1484
1485 /// <summary>
1486 /// This is our collision testing routine in ODE
1487 /// </summary>
1488 /// <param name="timeStep"></param>
1489 private void collision_optimized(float timeStep)
1490 {
1491 _perloopContact.Clear();
1492
1493 lock (_characters)
1494 {
1495 foreach (OdeCharacter chr in _characters)
1496 {
1497 // Reset the collision values to false
1498 // since we don't know if we're colliding yet
1499
1500 // For some reason this can happen. Don't ask...
1501 //
1502 if (chr == null)
1503 continue;
1504
1505 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1506 continue;
1507
1508 chr.IsColliding = false;
1509 chr.CollidingGround = false;
1510 chr.CollidingObj = false;
1511
1512 // test the avatar's geometry for collision with the space
1513 // This will return near and the space that they are the closest to
1514 // And we'll run this again against the avatar and the space segment
1515 // This will return with a bunch of possible objects in the space segment
1516 // and we'll run it again on all of them.
1517 try
1518 {
1519 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1520 }
1521 catch (AccessViolationException)
1522 {
1523 m_log.Warn("[PHYSICS]: Unable to space collide");
1524 }
1525 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1526 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1527 //{
1528 //chr.Position.Z = terrainheight + 10.0f;
1529 //forcedZ = true;
1530 //}
1531 }
1532 }
1533
1534 lock (_activeprims)
1535 {
1536 List<OdePrim> removeprims = null;
1537 foreach (OdePrim chr in _activeprims)
1538 {
1539 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1540 {
1541 try
1542 {
1543 lock (chr)
1544 {
1545 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1546 {
1547 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1548 }
1549 else
1550 {
1551 if (removeprims == null)
1552 {
1553 removeprims = new List<OdePrim>();
1554 }
1555 removeprims.Add(chr);
1556 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!");
1557 }
1558 }
1559 }
1560 catch (AccessViolationException)
1561 {
1562 m_log.Warn("[PHYSICS]: Unable to space collide");
1563 }
1564 }
1565 }
1566 if (removeprims != null)
1567 {
1568 foreach (OdePrim chr in removeprims)
1569 {
1570 _activeprims.Remove(chr);
1571 }
1572 }
1573 }
1574
1575 _perloopContact.Clear();
1576 }
1577
1578 #endregion
1579
1580 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1581 {
1582 m_worldOffset = offset;
1583 WorldExtents = new Vector2(extents.X, extents.Y);
1584 m_parentScene = pScene;
1585
1586 }
1587
1588 // Recovered for use by fly height. Kitto Flora
1589 public float GetTerrainHeightAtXY(float x, float y)
1590 {
1591
1592 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1593 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1594
1595 IntPtr heightFieldGeom = IntPtr.Zero;
1596
1597 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1598 {
1599 if (heightFieldGeom != IntPtr.Zero)
1600 {
1601 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1602 {
1603
1604 int index;
1605
1606
1607 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1608 (int)x < 0.001f || (int)y < 0.001f)
1609 return 0;
1610
1611 x = x - offsetX;
1612 y = y - offsetY;
1613
1614 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1615
1616 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1617 {
1618 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1619 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1620 }
1621
1622 else
1623 return 0f;
1624 }
1625 else
1626 {
1627 return 0f;
1628 }
1629
1630 }
1631 else
1632 {
1633 return 0f;
1634 }
1635
1636 }
1637 else
1638 {
1639 return 0f;
1640 }
1641
1642
1643 }
1644// End recovered. Kitto Flora
1645
1646 public void addCollisionEventReporting(PhysicsActor obj)
1647 {
1648 lock (_collisionEventPrim)
1649 {
1650 if (!_collisionEventPrim.Contains(obj))
1651 _collisionEventPrim.Add(obj);
1652 }
1653 }
1654
1655 public void remCollisionEventReporting(PhysicsActor obj)
1656 {
1657 lock (_collisionEventPrim)
1658 {
1659 if (!_collisionEventPrim.Contains(obj))
1660 _collisionEventPrim.Remove(obj);
1661 }
1662 }
1663
1664 #region Add/Remove Entities
1665
1666 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1667 {
1668 Vector3 pos;
1669 pos.X = position.X;
1670 pos.Y = position.Y;
1671 pos.Z = position.Z;
1672 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1673 newAv.Flying = isFlying;
1674 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1675
1676 return newAv;
1677 }
1678
1679 public void AddCharacter(OdeCharacter chr)
1680 {
1681 lock (_characters)
1682 {
1683 if (!_characters.Contains(chr))
1684 {
1685 _characters.Add(chr);
1686 if (chr.bad)
1687 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1688 }
1689 }
1690 }
1691
1692 public void RemoveCharacter(OdeCharacter chr)
1693 {
1694 lock (_characters)
1695 {
1696 if (_characters.Contains(chr))
1697 {
1698 _characters.Remove(chr);
1699 }
1700 }
1701 }
1702 public void BadCharacter(OdeCharacter chr)
1703 {
1704 lock (_badCharacter)
1705 {
1706 if (!_badCharacter.Contains(chr))
1707 _badCharacter.Add(chr);
1708 }
1709 }
1710
1711 public override void RemoveAvatar(PhysicsActor actor)
1712 {
1713 //m_log.Debug("[PHYSICS]:ODELOCK");
1714 ((OdeCharacter) actor).Destroy();
1715
1716 }
1717
1718 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1719 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1720 {
1721
1722 Vector3 pos = position;
1723 Vector3 siz = size;
1724 Quaternion rot = rotation;
1725
1726 OdePrim newPrim;
1727 lock (OdeLock)
1728 {
1729 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1730
1731 lock (_prims)
1732 _prims.Add(newPrim);
1733 }
1734
1735 return newPrim;
1736 }
1737
1738 public void addActivePrim(OdePrim activatePrim)
1739 {
1740 // adds active prim.. (ones that should be iterated over in collisions_optimized
1741 lock (_activeprims)
1742 {
1743 if (!_activeprims.Contains(activatePrim))
1744 _activeprims.Add(activatePrim);
1745 //else
1746 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1747 }
1748 }
1749
1750 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1751 Vector3 size, Quaternion rotation) //To be removed
1752 {
1753 return AddPrimShape(primName, pbs, position, size, rotation, false);
1754 }
1755
1756 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1757 Vector3 size, Quaternion rotation, bool isPhysical)
1758 {
1759 PhysicsActor result;
1760 IMesh mesh = null;
1761
1762 if (needsMeshing(pbs))
1763 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1764
1765 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1766
1767 return result;
1768 }
1769
1770 public override float TimeDilation
1771 {
1772 get { return m_timeDilation; }
1773 }
1774
1775 public override bool SupportsNINJAJoints
1776 {
1777 get { return m_NINJA_physics_joints_enabled; }
1778 }
1779
1780 // internal utility function: must be called within a lock (OdeLock)
1781 private void InternalAddActiveJoint(PhysicsJoint joint)
1782 {
1783 activeJoints.Add(joint);
1784 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1785 }
1786
1787 // internal utility function: must be called within a lock (OdeLock)
1788 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1789 {
1790 pendingJoints.Add(joint);
1791 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1792 }
1793
1794 // internal utility function: must be called within a lock (OdeLock)
1795 private void InternalRemovePendingJoint(PhysicsJoint joint)
1796 {
1797 pendingJoints.Remove(joint);
1798 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1799 }
1800
1801 // internal utility function: must be called within a lock (OdeLock)
1802 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1803 {
1804 activeJoints.Remove(joint);
1805 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1806 }
1807
1808 public override void DumpJointInfo()
1809 {
1810 string hdr = "[NINJA] JOINTINFO: ";
1811 foreach (PhysicsJoint j in pendingJoints)
1812 {
1813 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1814 }
1815 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1816 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1817 {
1818 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1819 }
1820 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1821 foreach (PhysicsJoint j in activeJoints)
1822 {
1823 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1824 }
1825 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1826 foreach (string jointName in SOPName_to_activeJoint.Keys)
1827 {
1828 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1829 }
1830 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1831
1832 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1833 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1834 foreach (string actorName in joints_connecting_actor.Keys)
1835 {
1836 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1837 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1838 {
1839 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1840 }
1841 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1842 }
1843 }
1844
1845 public override void RequestJointDeletion(string ObjectNameInScene)
1846 {
1847 lock (externalJointRequestsLock)
1848 {
1849 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1850 {
1851 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1852 }
1853 }
1854 }
1855
1856 private void DeleteRequestedJoints()
1857 {
1858 List<string> myRequestedJointsToBeDeleted;
1859 lock (externalJointRequestsLock)
1860 {
1861 // make a local copy of the shared list for processing (threading issues)
1862 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1863 }
1864
1865 foreach (string jointName in myRequestedJointsToBeDeleted)
1866 {
1867 lock (OdeLock)
1868 {
1869 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1870 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1871 {
1872 OdePhysicsJoint joint = null;
1873 if (SOPName_to_activeJoint.ContainsKey(jointName))
1874 {
1875 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1876 InternalRemoveActiveJoint(joint);
1877 }
1878 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1879 {
1880 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1881 InternalRemovePendingJoint(joint);
1882 }
1883
1884 if (joint != null)
1885 {
1886 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1887 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1888 {
1889 string bodyName = joint.BodyNames[iBodyName];
1890 if (bodyName != "NULL")
1891 {
1892 joints_connecting_actor[bodyName].Remove(joint);
1893 if (joints_connecting_actor[bodyName].Count == 0)
1894 {
1895 joints_connecting_actor.Remove(bodyName);
1896 }
1897 }
1898 }
1899
1900 DoJointDeactivated(joint);
1901 if (joint.jointID != IntPtr.Zero)
1902 {
1903 d.JointDestroy(joint.jointID);
1904 joint.jointID = IntPtr.Zero;
1905 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1906 }
1907 else
1908 {
1909 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1910 }
1911 }
1912 else
1913 {
1914 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1915 }
1916 }
1917 else
1918 {
1919 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1920 }
1921 }
1922 }
1923
1924 // remove processed joints from the shared list
1925 lock (externalJointRequestsLock)
1926 {
1927 foreach (string jointName in myRequestedJointsToBeDeleted)
1928 {
1929 requestedJointsToBeDeleted.Remove(jointName);
1930 }
1931 }
1932 }
1933
1934 // for pending joints we don't know if their associated bodies exist yet or not.
1935 // the joint is actually created during processing of the taints
1936 private void CreateRequestedJoints()
1937 {
1938 List<PhysicsJoint> myRequestedJointsToBeCreated;
1939 lock (externalJointRequestsLock)
1940 {
1941 // make a local copy of the shared list for processing (threading issues)
1942 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1943 }
1944
1945 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1946 {
1947 lock (OdeLock)
1948 {
1949 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1950 {
1951 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);
1952 continue;
1953 }
1954 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1955 {
1956 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);
1957 continue;
1958 }
1959
1960 InternalAddPendingJoint(joint as OdePhysicsJoint);
1961
1962 if (joint.BodyNames.Count >= 2)
1963 {
1964 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1965 {
1966 string bodyName = joint.BodyNames[iBodyName];
1967 if (bodyName != "NULL")
1968 {
1969 if (!joints_connecting_actor.ContainsKey(bodyName))
1970 {
1971 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1972 }
1973 joints_connecting_actor[bodyName].Add(joint);
1974 }
1975 }
1976 }
1977 }
1978 }
1979
1980 // remove processed joints from shared list
1981 lock (externalJointRequestsLock)
1982 {
1983 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1984 {
1985 requestedJointsToBeCreated.Remove(joint);
1986 }
1987 }
1988
1989 }
1990
1991 // public function to add an request for joint creation
1992 // this joint will just be added to a waiting list that is NOT processed during the main
1993 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
1994
1995 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
1996 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
1997
1998 {
1999
2000 OdePhysicsJoint joint = new OdePhysicsJoint();
2001 joint.ObjectNameInScene = objectNameInScene;
2002 joint.Type = jointType;
2003 joint.Position = position;
2004 joint.Rotation = rotation;
2005 joint.RawParams = parms;
2006 joint.BodyNames = new List<string>(bodyNames);
2007 joint.TrackedBodyName = trackedBodyName;
2008 joint.LocalRotation = localRotation;
2009 joint.jointID = IntPtr.Zero;
2010 joint.ErrorMessageCount = 0;
2011
2012 lock (externalJointRequestsLock)
2013 {
2014 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2015 {
2016 requestedJointsToBeCreated.Add(joint);
2017 }
2018 }
2019 return joint;
2020 }
2021
2022 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2023 {
2024 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2025 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2026 {
2027
2028 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2029 //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)
2030 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2031 {
2032 jointsToRemove.Add(j);
2033 }
2034 foreach (PhysicsJoint j in jointsToRemove)
2035 {
2036 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2037 RequestJointDeletion(j.ObjectNameInScene);
2038 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2039 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)
2040 }
2041 }
2042 }
2043
2044 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2045 {
2046 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2047 lock (OdeLock)
2048 {
2049 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2050 RemoveAllJointsConnectedToActor(actor);
2051 }
2052 }
2053
2054 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2055 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2056 {
2057 Debug.Assert(joint.IsInPhysicsEngine);
2058 d.Vector3 pos = new d.Vector3();
2059
2060 if (!(joint is OdePhysicsJoint))
2061 {
2062 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2063 }
2064 else
2065 {
2066 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2067 switch (odeJoint.Type)
2068 {
2069 case PhysicsJointType.Ball:
2070 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2071 break;
2072 case PhysicsJointType.Hinge:
2073 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2074 break;
2075 }
2076 }
2077 return new Vector3(pos.X, pos.Y, pos.Z);
2078 }
2079
2080 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2081 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2082 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2083 // keeping track of the joint's original orientation relative to one of the involved bodies.
2084 public override Vector3 GetJointAxis(PhysicsJoint joint)
2085 {
2086 Debug.Assert(joint.IsInPhysicsEngine);
2087 d.Vector3 axis = new d.Vector3();
2088
2089 if (!(joint is OdePhysicsJoint))
2090 {
2091 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2092 }
2093 else
2094 {
2095 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2096 switch (odeJoint.Type)
2097 {
2098 case PhysicsJointType.Ball:
2099 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2100 break;
2101 case PhysicsJointType.Hinge:
2102 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2103 break;
2104 }
2105 }
2106 return new Vector3(axis.X, axis.Y, axis.Z);
2107 }
2108
2109
2110 public void remActivePrim(OdePrim deactivatePrim)
2111 {
2112 lock (_activeprims)
2113 {
2114 _activeprims.Remove(deactivatePrim);
2115 }
2116 }
2117
2118 public override void RemovePrim(PhysicsActor prim)
2119 {
2120 if (prim is OdePrim)
2121 {
2122 lock (OdeLock)
2123 {
2124 OdePrim p = (OdePrim) prim;
2125
2126 p.setPrimForRemoval();
2127 AddPhysicsActorTaint(prim);
2128 //RemovePrimThreadLocked(p);
2129 }
2130 }
2131 }
2132
2133 /// <summary>
2134 /// This is called from within simulate but outside the locked portion
2135 /// We need to do our own locking here
2136 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2137 ///
2138 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2139 /// that the space was using.
2140 /// </summary>
2141 /// <param name="prim"></param>
2142 public void RemovePrimThreadLocked(OdePrim prim)
2143 {
2144//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2145 lock (prim)
2146 {
2147 remCollisionEventReporting(prim);
2148 lock (ode)
2149 {
2150 if (prim.prim_geom != IntPtr.Zero)
2151 {
2152 prim.ResetTaints();
2153
2154 if (prim.IsPhysical)
2155 {
2156 prim.disableBody();
2157 if (prim.childPrim)
2158 {
2159 prim.childPrim = false;
2160 prim.Body = IntPtr.Zero;
2161 prim.m_disabled = true;
2162 prim.IsPhysical = false;
2163 }
2164
2165
2166 }
2167 // we don't want to remove the main space
2168
2169 // If the geometry is in the targetspace, remove it from the target space
2170 //m_log.Warn(prim.m_targetSpace);
2171
2172 //if (prim.m_targetSpace != IntPtr.Zero)
2173 //{
2174 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2175 //{
2176
2177 //if (d.GeomIsSpace(prim.m_targetSpace))
2178 //{
2179 //waitForSpaceUnlock(prim.m_targetSpace);
2180 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2181 prim.m_targetSpace = IntPtr.Zero;
2182 //}
2183 //else
2184 //{
2185 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2186 //((OdePrim)prim).m_targetSpace.ToString());
2187 //}
2188
2189 //}
2190 //}
2191 //m_log.Warn(prim.prim_geom);
2192 try
2193 {
2194 if (prim.prim_geom != IntPtr.Zero)
2195 {
2196
2197//string tPA;
2198//geom_name_map.TryGetValue(prim.prim_geom, out tPA);
2199//Console.WriteLine("**** Remove {0}", tPA);
2200 if(geom_name_map.ContainsKey(prim.prim_geom)) geom_name_map.Remove(prim.prim_geom);
2201 if(actor_name_map.ContainsKey(prim.prim_geom)) actor_name_map.Remove(prim.prim_geom);
2202 d.GeomDestroy(prim.prim_geom);
2203 prim.prim_geom = IntPtr.Zero;
2204 }
2205 else
2206 {
2207 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2208 }
2209 }
2210 catch (AccessViolationException)
2211 {
2212 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2213 }
2214 lock (_prims)
2215 _prims.Remove(prim);
2216
2217 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2218 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2219 //{
2220 //if (prim.m_targetSpace != null)
2221 //{
2222 //if (d.GeomIsSpace(prim.m_targetSpace))
2223 //{
2224 //waitForSpaceUnlock(prim.m_targetSpace);
2225 //d.SpaceRemove(space, prim.m_targetSpace);
2226 // free up memory used by the space.
2227 //d.SpaceDestroy(prim.m_targetSpace);
2228 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2229 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2230 //}
2231 //else
2232 //{
2233 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2234 //((OdePrim) prim).m_targetSpace.ToString());
2235 //}
2236 //}
2237 //}
2238
2239 if (SupportsNINJAJoints)
2240 {
2241 RemoveAllJointsConnectedToActorThreadLocked(prim);
2242 }
2243 }
2244 }
2245 }
2246 }
2247
2248 #endregion
2249
2250 #region Space Separation Calculation
2251
2252 /// <summary>
2253 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2254 /// </summary>
2255 /// <param name="pSpace"></param>
2256 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2257 {
2258 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2259 {
2260 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2261 {
2262 if (staticPrimspace[x, y] == pSpace)
2263 staticPrimspace[x, y] = IntPtr.Zero;
2264 }
2265 }
2266 }
2267
2268 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2269 {
2270 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2271 }
2272
2273 /// <summary>
2274 /// Called when a static prim moves. Allocates a space for the prim based on its position
2275 /// </summary>
2276 /// <param name="geom">the pointer to the geom that moved</param>
2277 /// <param name="pos">the position that the geom moved to</param>
2278 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2279 /// <returns>a pointer to the new space it's in</returns>
2280 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2281 {
2282 // Called from setting the Position and Size of an ODEPrim so
2283 // it's already in locked space.
2284
2285 // we don't want to remove the main space
2286 // we don't need to test physical here because this function should
2287 // never be called if the prim is physical(active)
2288
2289 // All physical prim end up in the root space
2290 //Thread.Sleep(20);
2291 if (currentspace != space)
2292 {
2293 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2294 //if (currentspace == IntPtr.Zero)
2295 //{
2296 //int adfadf = 0;
2297 //}
2298 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2299 {
2300 if (d.GeomIsSpace(currentspace))
2301 {
2302 waitForSpaceUnlock(currentspace);
2303 d.SpaceRemove(currentspace, geom);
2304 }
2305 else
2306 {
2307 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2308 " Geom:" + geom);
2309 }
2310 }
2311 else
2312 {
2313 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2314 if (sGeomIsIn != IntPtr.Zero)
2315 {
2316 if (d.GeomIsSpace(currentspace))
2317 {
2318 waitForSpaceUnlock(sGeomIsIn);
2319 d.SpaceRemove(sGeomIsIn, geom);
2320 }
2321 else
2322 {
2323 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2324 sGeomIsIn + " Geom:" + geom);
2325 }
2326 }
2327 }
2328
2329 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2330 if (d.SpaceGetNumGeoms(currentspace) == 0)
2331 {
2332 if (currentspace != IntPtr.Zero)
2333 {
2334 if (d.GeomIsSpace(currentspace))
2335 {
2336 waitForSpaceUnlock(currentspace);
2337 waitForSpaceUnlock(space);
2338 d.SpaceRemove(space, currentspace);
2339 // free up memory used by the space.
2340
2341 //d.SpaceDestroy(currentspace);
2342 resetSpaceArrayItemToZero(currentspace);
2343 }
2344 else
2345 {
2346 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2347 currentspace + " Geom:" + geom);
2348 }
2349 }
2350 }
2351 }
2352 else
2353 {
2354 // this is a physical object that got disabled. ;.;
2355 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2356 {
2357 if (d.SpaceQuery(currentspace, geom))
2358 {
2359 if (d.GeomIsSpace(currentspace))
2360 {
2361 waitForSpaceUnlock(currentspace);
2362 d.SpaceRemove(currentspace, geom);
2363 }
2364 else
2365 {
2366 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2367 currentspace + " Geom:" + geom);
2368 }
2369 }
2370 else
2371 {
2372 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2373 if (sGeomIsIn != IntPtr.Zero)
2374 {
2375 if (d.GeomIsSpace(sGeomIsIn))
2376 {
2377 waitForSpaceUnlock(sGeomIsIn);
2378 d.SpaceRemove(sGeomIsIn, geom);
2379 }
2380 else
2381 {
2382 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2383 sGeomIsIn + " Geom:" + geom);
2384 }
2385 }
2386 }
2387 }
2388 }
2389
2390 // The routines in the Position and Size sections do the 'inserting' into the space,
2391 // so all we have to do is make sure that the space that we're putting the prim into
2392 // is in the 'main' space.
2393 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2394 IntPtr newspace = calculateSpaceForGeom(pos);
2395
2396 if (newspace == IntPtr.Zero)
2397 {
2398 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2399 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2400 }
2401
2402 return newspace;
2403 }
2404
2405 /// <summary>
2406 /// Creates a new space at X Y
2407 /// </summary>
2408 /// <param name="iprimspaceArrItemX"></param>
2409 /// <param name="iprimspaceArrItemY"></param>
2410 /// <returns>A pointer to the created space</returns>
2411 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2412 {
2413 // creating a new space for prim and inserting it into main space.
2414 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2415 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2416 waitForSpaceUnlock(space);
2417 d.SpaceSetSublevel(space, 1);
2418 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2419 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2420 }
2421
2422 /// <summary>
2423 /// Calculates the space the prim should be in by its position
2424 /// </summary>
2425 /// <param name="pos"></param>
2426 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2427 public IntPtr calculateSpaceForGeom(Vector3 pos)
2428 {
2429 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2430 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2431 return staticPrimspace[xyspace[0], xyspace[1]];
2432 }
2433
2434 /// <summary>
2435 /// Holds the space allocation logic
2436 /// </summary>
2437 /// <param name="pos"></param>
2438 /// <returns>an array item based on the position</returns>
2439 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2440 {
2441 int[] returnint = new int[2];
2442
2443 returnint[0] = (int) (pos.X/metersInSpace);
2444
2445 if (returnint[0] > ((int) (259f/metersInSpace)))
2446 returnint[0] = ((int) (259f/metersInSpace));
2447 if (returnint[0] < 0)
2448 returnint[0] = 0;
2449
2450 returnint[1] = (int) (pos.Y/metersInSpace);
2451 if (returnint[1] > ((int) (259f/metersInSpace)))
2452 returnint[1] = ((int) (259f/metersInSpace));
2453 if (returnint[1] < 0)
2454 returnint[1] = 0;
2455
2456 return returnint;
2457 }
2458
2459 #endregion
2460
2461 /// <summary>
2462 /// Routine to figure out if we need to mesh this prim with our mesher
2463 /// </summary>
2464 /// <param name="pbs"></param>
2465 /// <returns></returns>
2466 public bool needsMeshing(PrimitiveBaseShape pbs)
2467 {
2468 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2469 // but we still need to check for sculptie meshing being enabled so this is the most
2470 // convenient place to do it for now...
2471
2472 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2473 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2474 int iPropertiesNotSupportedDefault = 0;
2475
2476 if (pbs.SculptEntry && !meshSculptedPrim)
2477 {
2478#if SPAM
2479 m_log.Warn("NonMesh");
2480#endif
2481 return false;
2482 }
2483
2484 // 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
2485 if (!forceSimplePrimMeshing)
2486 {
2487 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2488 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2489 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2490 {
2491
2492 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2493 && pbs.ProfileHollow == 0
2494 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2495 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2496 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2497 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2498 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2499 {
2500#if SPAM
2501 m_log.Warn("NonMesh");
2502#endif
2503 return false;
2504 }
2505 }
2506 }
2507
2508 if (pbs.ProfileHollow != 0)
2509 iPropertiesNotSupportedDefault++;
2510
2511 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2512 iPropertiesNotSupportedDefault++;
2513
2514 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2515 iPropertiesNotSupportedDefault++;
2516
2517 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2518 iPropertiesNotSupportedDefault++;
2519
2520 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2521 iPropertiesNotSupportedDefault++;
2522
2523 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2524 iPropertiesNotSupportedDefault++;
2525
2526 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))
2527 iPropertiesNotSupportedDefault++;
2528
2529 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2530 iPropertiesNotSupportedDefault++;
2531
2532 // test for torus
2533 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2534 {
2535 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2536 {
2537 iPropertiesNotSupportedDefault++;
2538 }
2539 }
2540 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2541 {
2542 if (pbs.PathCurve == (byte)Extrusion.Straight)
2543 {
2544 iPropertiesNotSupportedDefault++;
2545 }
2546
2547 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2548 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2549 {
2550 iPropertiesNotSupportedDefault++;
2551 }
2552 }
2553 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2554 {
2555 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2556 {
2557 iPropertiesNotSupportedDefault++;
2558 }
2559 }
2560 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2561 {
2562 if (pbs.PathCurve == (byte)Extrusion.Straight)
2563 {
2564 iPropertiesNotSupportedDefault++;
2565 }
2566 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2567 {
2568 iPropertiesNotSupportedDefault++;
2569 }
2570 }
2571
2572
2573 if (iPropertiesNotSupportedDefault == 0)
2574 {
2575#if SPAM
2576 m_log.Warn("NonMesh");
2577#endif
2578 return false;
2579 }
2580#if SPAM
2581 m_log.Debug("Mesh");
2582#endif
2583 return true;
2584 }
2585
2586 /// <summary>
2587 /// Called after our prim properties are set Scale, position etc.
2588 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2589 /// This assures us that we have no race conditions
2590 /// </summary>
2591 /// <param name="prim"></param>
2592 public override void AddPhysicsActorTaint(PhysicsActor prim)
2593 {
2594
2595 if (prim is OdePrim)
2596 {
2597 OdePrim taintedprim = ((OdePrim) prim);
2598 lock (_taintedPrimLock)
2599 {
2600 if (!(_taintedPrimH.Contains(taintedprim)))
2601 {
2602//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2603 _taintedPrimH.Add(taintedprim); // HashSet for searching
2604 _taintedPrimL.Add(taintedprim); // List for ordered readout
2605 }
2606 }
2607 return;
2608 }
2609 else if (prim is OdeCharacter)
2610 {
2611 OdeCharacter taintedchar = ((OdeCharacter)prim);
2612 lock (_taintedActors)
2613 {
2614 if (!(_taintedActors.Contains(taintedchar)))
2615 {
2616 _taintedActors.Add(taintedchar);
2617 if (taintedchar.bad)
2618 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2619 }
2620 }
2621 }
2622 }
2623
2624 /// <summary>
2625 /// This is our main simulate loop
2626 /// It's thread locked by a Mutex in the scene.
2627 /// It holds Collisions, it instructs ODE to step through the physical reactions
2628 /// It moves the objects around in memory
2629 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2630 /// </summary>
2631 /// <param name="timeStep"></param>
2632 /// <returns></returns>
2633 public override float Simulate(float timeStep)
2634 {
2635 if (framecount >= int.MaxValue)
2636 framecount = 0;
2637 //if (m_worldOffset != Vector3.Zero)
2638 // return 0;
2639
2640 framecount++;
2641
2642 DateTime now = DateTime.UtcNow;
2643 TimeSpan SinceLastFrame = now - m_lastframe;
2644 m_lastframe = now;
2645 float realtime = (float)SinceLastFrame.TotalSeconds;
2646// Console.WriteLine("ts={0} rt={1}", timeStep, realtime);
2647 timeStep = realtime;
2648
2649 // float fps = 1.0f / realtime;
2650 float fps = 0.0f; // number of ODE steps in this Simulate step
2651 //m_log.Info(timeStep.ToString());
2652 step_time += timeStep;
2653
2654 // If We're loaded down by something else,
2655 // or debugging with the Visual Studio project on pause
2656 // skip a few frames to catch up gracefully.
2657 // without shooting the physicsactors all over the place
2658
2659 if (step_time >= m_SkipFramesAtms)
2660 {
2661 // Instead of trying to catch up, it'll do 5 physics frames only
2662 step_time = ODE_STEPSIZE;
2663 m_physicsiterations = 5;
2664 }
2665 else
2666 {
2667 m_physicsiterations = 10;
2668 }
2669
2670 if (SupportsNINJAJoints)
2671 {
2672 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2673 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2674 }
2675
2676 lock (OdeLock)
2677 {
2678 // Process 10 frames if the sim is running normal..
2679 // process 5 frames if the sim is running slow
2680 //try
2681 //{
2682 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2683 //}
2684 //catch (StackOverflowException)
2685 //{
2686 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2687 // ode.drelease(world);
2688 //base.TriggerPhysicsBasedRestart();
2689 //}
2690
2691 int i = 0;
2692
2693 // Figure out the Frames Per Second we're going at.
2694 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2695
2696 // fps = (step_time / ODE_STEPSIZE) * 1000;
2697 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2698 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2699
2700 // step_time = 0.09375f;
2701
2702 while (step_time > 0.0f)
2703 {
2704 //lock (ode)
2705 //{
2706 //if (!ode.lockquery())
2707 //{
2708 // ode.dlock(world);
2709 try
2710 {
2711 // Insert, remove Characters
2712 bool processedtaints = false;
2713
2714 lock (_taintedActors)
2715 {
2716 if (_taintedActors.Count > 0)
2717 {
2718 foreach (OdeCharacter character in _taintedActors)
2719 {
2720
2721 character.ProcessTaints(ODE_STEPSIZE);
2722
2723 processedtaints = true;
2724 //character.m_collisionscore = 0;
2725 }
2726
2727 if (processedtaints)
2728 _taintedActors.Clear();
2729 }
2730 } // end lock _taintedActors
2731
2732 // Modify other objects in the scene.
2733 processedtaints = false;
2734
2735 lock (_taintedPrimLock)
2736 {
2737 foreach (OdePrim prim in _taintedPrimL)
2738 {
2739 if (prim.m_taintremove)
2740 {
2741 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2742 RemovePrimThreadLocked(prim);
2743 }
2744 else
2745 {
2746 //Console.WriteLine("Simulate calls ProcessTaints");
2747 prim.ProcessTaints(ODE_STEPSIZE);
2748 }
2749 processedtaints = true;
2750 prim.m_collisionscore = 0;
2751
2752 // This loop can block up the Heartbeat for a very long time on large regions.
2753 // We need to let the Watchdog know that the Heartbeat is not dead
2754 // NOTE: This is currently commented out, but if things like OAR loading are
2755 // timing the heartbeat out we will need to uncomment it
2756 //Watchdog.UpdateThread();
2757 }
2758
2759 if (SupportsNINJAJoints)
2760 {
2761 // Create pending joints, if possible
2762
2763 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2764 // a joint requires specifying the body id of both involved bodies
2765 if (pendingJoints.Count > 0)
2766 {
2767 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2768 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2769 foreach (PhysicsJoint joint in pendingJoints)
2770 {
2771 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2772 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(),
2773 System.StringSplitOptions.RemoveEmptyEntries);
2774 List<IntPtr> jointBodies = new List<IntPtr>();
2775 bool allJointBodiesAreReady = true;
2776 foreach (string jointParam in jointParams)
2777 {
2778 if (jointParam == "NULL")
2779 {
2780 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2781 jointBodies.Add(IntPtr.Zero);
2782 }
2783 else
2784 {
2785 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2786 bool foundPrim = false;
2787 lock (_prims)
2788 {
2789 foreach (OdePrim prim in _prims) // FIXME: inefficient
2790 {
2791 if (prim.SOPName == jointParam)
2792 {
2793 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2794 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2795 {
2796 jointBodies.Add(prim.Body);
2797 foundPrim = true;
2798 break;
2799 }
2800 else
2801 {
2802 DoJointErrorMessage(joint, "prim name " + jointParam +
2803 " exists but is not (yet) physical; deferring joint creation. " +
2804 "IsPhysical property is " + prim.IsPhysical +
2805 " and body is " + prim.Body);
2806 foundPrim = false;
2807 break;
2808 }
2809 }
2810 }
2811 }
2812 if (foundPrim)
2813 {
2814 // all is fine
2815 }
2816 else
2817 {
2818 allJointBodiesAreReady = false;
2819 break;
2820 }
2821 }
2822 }
2823 if (allJointBodiesAreReady)
2824 {
2825 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2826 if (jointBodies[0] == jointBodies[1])
2827 {
2828 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2829 }
2830 else
2831 {
2832 switch (joint.Type)
2833 {
2834 case PhysicsJointType.Ball:
2835 {
2836 IntPtr odeJoint;
2837 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2838 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2839 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2840 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2841 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2842 d.JointSetBallAnchor(odeJoint,
2843 joint.Position.X,
2844 joint.Position.Y,
2845 joint.Position.Z);
2846 //DoJointErrorMessage(joint, "ODE joint setting OK");
2847 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2848 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2849 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2850 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2851
2852 if (joint is OdePhysicsJoint)
2853 {
2854 ((OdePhysicsJoint)joint).jointID = odeJoint;
2855 }
2856 else
2857 {
2858 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2859 }
2860 }
2861 break;
2862 case PhysicsJointType.Hinge:
2863 {
2864 IntPtr odeJoint;
2865 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2866 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2867 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2868 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2869 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2870 d.JointSetHingeAnchor(odeJoint,
2871 joint.Position.X,
2872 joint.Position.Y,
2873 joint.Position.Z);
2874 // We use the orientation of the x-axis of the joint's coordinate frame
2875 // as the axis for the hinge.
2876
2877 // Therefore, we must get the joint's coordinate frame based on the
2878 // joint.Rotation field, which originates from the orientation of the
2879 // joint's proxy object in the scene.
2880
2881 // The joint's coordinate frame is defined as the transformation matrix
2882 // that converts a vector from joint-local coordinates into world coordinates.
2883 // World coordinates are defined as the XYZ coordinate system of the sim,
2884 // as shown in the top status-bar of the viewer.
2885
2886 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2887 // and use that as the hinge axis.
2888
2889 //joint.Rotation.Normalize();
2890 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2891
2892 // Now extract the X axis of the joint's coordinate frame.
2893
2894 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2895 // tar pit of transposed, inverted, and generally messed-up orientations.
2896 // (In other words, Matrix4.AtAxis() is borked.)
2897 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2898
2899 // Instead, compute the X axis of the coordinate frame by transforming
2900 // the (1,0,0) vector. At least that works.
2901
2902 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2903 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2904 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2905 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2906 d.JointSetHingeAxis(odeJoint,
2907 jointAxis.X,
2908 jointAxis.Y,
2909 jointAxis.Z);
2910 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2911 if (joint is OdePhysicsJoint)
2912 {
2913 ((OdePhysicsJoint)joint).jointID = odeJoint;
2914 }
2915 else
2916 {
2917 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2918 }
2919 }
2920 break;
2921 }
2922 successfullyProcessedPendingJoints.Add(joint);
2923 }
2924 }
2925 else
2926 {
2927 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2928 }
2929 }
2930 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2931 {
2932 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2933 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2934 InternalRemovePendingJoint(successfullyProcessedJoint);
2935 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2936 InternalAddActiveJoint(successfullyProcessedJoint);
2937 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2938 }
2939 }
2940 } // end SupportsNINJAJoints
2941
2942 if (processedtaints)
2943//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2944 _taintedPrimH.Clear(); // ??? if this only ???
2945 _taintedPrimL.Clear();
2946 } // end lock _taintedPrimLock
2947
2948 // Move characters
2949 lock (_characters)
2950 {
2951 List<OdeCharacter> defects = new List<OdeCharacter>();
2952 foreach (OdeCharacter actor in _characters)
2953 {
2954 if (actor != null)
2955 actor.Move(ODE_STEPSIZE, defects);
2956 }
2957 if (0 != defects.Count)
2958 {
2959 foreach (OdeCharacter defect in defects)
2960 {
2961 RemoveCharacter(defect);
2962 }
2963 }
2964 } // end lock _characters
2965
2966 // Move other active objects
2967 lock (_activeprims)
2968 {
2969 foreach (OdePrim prim in _activeprims)
2970 {
2971 prim.m_collisionscore = 0;
2972 prim.Move(ODE_STEPSIZE);
2973 }
2974 } // end lock _activeprims
2975
2976 //if ((framecount % m_randomizeWater) == 0)
2977 // randomizeWater(waterlevel);
2978
2979 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2980 m_rayCastManager.ProcessQueuedRequests();
2981
2982 collision_optimized(ODE_STEPSIZE);
2983
2984 lock (_collisionEventPrim)
2985 {
2986 foreach (PhysicsActor obj in _collisionEventPrim)
2987 {
2988 if (obj == null)
2989 continue;
2990
2991 switch ((ActorTypes)obj.PhysicsActorType)
2992 {
2993 case ActorTypes.Agent:
2994 OdeCharacter cobj = (OdeCharacter)obj;
2995 cobj.AddCollisionFrameTime(100);
2996 cobj.SendCollisions();
2997 break;
2998 case ActorTypes.Prim:
2999 OdePrim pobj = (OdePrim)obj;
3000 pobj.SendCollisions();
3001 break;
3002 }
3003 }
3004 } // end lock _collisionEventPrim
3005
3006 //if (m_global_contactcount > 5)
3007 //{
3008 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3009 //}
3010
3011 m_global_contactcount = 0;
3012
3013 d.WorldQuickStep(world, ODE_STEPSIZE);
3014 d.JointGroupEmpty(contactgroup);
3015 fps++;
3016 //ode.dunlock(world);
3017 } // end try
3018 catch (Exception e)
3019 {
3020 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3021 ode.dunlock(world);
3022 }
3023
3024 step_time -= ODE_STEPSIZE;
3025 i++;
3026 //}
3027 //else
3028 //{
3029 //fps = 0;
3030 //}
3031 //}
3032 } // end while (step_time > 0.0f)
3033
3034 lock (_characters)
3035 {
3036 foreach (OdeCharacter actor in _characters)
3037 {
3038 if (actor != null)
3039 {
3040 if (actor.bad)
3041 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3042 actor.UpdatePositionAndVelocity();
3043 }
3044 }
3045 }
3046
3047 lock (_badCharacter)
3048 {
3049 if (_badCharacter.Count > 0)
3050 {
3051 foreach (OdeCharacter chr in _badCharacter)
3052 {
3053 RemoveCharacter(chr);
3054 }
3055 _badCharacter.Clear();
3056 }
3057 }
3058
3059 lock (_activeprims)
3060 {
3061 //if (timeStep < 0.2f)
3062 {
3063 foreach (OdePrim actor in _activeprims)
3064 {
3065 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3066 {
3067 actor.UpdatePositionAndVelocity();
3068
3069 if (SupportsNINJAJoints)
3070 {
3071 // If an actor moved, move its joint proxy objects as well.
3072 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3073 // for this purpose but it is never called! So we just do the joint
3074 // movement code here.
3075
3076 if (actor.SOPName != null &&
3077 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3078 joints_connecting_actor[actor.SOPName] != null &&
3079 joints_connecting_actor[actor.SOPName].Count > 0)
3080 {
3081 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3082 {
3083 if (affectedJoint.IsInPhysicsEngine)
3084 {
3085 DoJointMoved(affectedJoint);
3086 }
3087 else
3088 {
3089 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);
3090 }
3091 }
3092 }
3093 }
3094 }
3095 }
3096 }
3097 } // end lock _activeprims
3098
3099 //DumpJointInfo();
3100
3101 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3102 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3103 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3104 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3105 {
3106 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3107 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3108
3109 if (physics_logging_append_existing_logfile)
3110 {
3111 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3112 TextWriter fwriter = File.AppendText(fname);
3113 fwriter.WriteLine(header);
3114 fwriter.Close();
3115 }
3116 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3117 }
3118 } // end lock OdeLock
3119
3120 return fps * 1000.0f; //NB This is a FRAME COUNT, not a time! AND is divide by 1000 in SimStatusReporter!
3121 } // end Simulate
3122
3123 public override void GetResults()
3124 {
3125 }
3126
3127 public override bool IsThreaded
3128 {
3129 // for now we won't be multithreaded
3130 get { return (false); }
3131 }
3132
3133 #region ODE Specific Terrain Fixes
3134 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3135 {
3136 float[] returnarr = new float[262144];
3137 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3138
3139 // Filling out the array into its multi-dimensional components
3140 for (int y = 0; y < WorldExtents.Y; y++)
3141 {
3142 for (int x = 0; x < WorldExtents.X; x++)
3143 {
3144 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3145 }
3146 }
3147
3148 // Resize using Nearest Neighbour
3149
3150 // This particular way is quick but it only works on a multiple of the original
3151
3152 // The idea behind this method can be described with the following diagrams
3153 // second pass and third pass happen in the same loop really.. just separated
3154 // them to show what this does.
3155
3156 // First Pass
3157 // ResultArr:
3158 // 1,1,1,1,1,1
3159 // 1,1,1,1,1,1
3160 // 1,1,1,1,1,1
3161 // 1,1,1,1,1,1
3162 // 1,1,1,1,1,1
3163 // 1,1,1,1,1,1
3164
3165 // Second Pass
3166 // ResultArr2:
3167 // 1,,1,,1,,1,,1,,1,
3168 // ,,,,,,,,,,
3169 // 1,,1,,1,,1,,1,,1,
3170 // ,,,,,,,,,,
3171 // 1,,1,,1,,1,,1,,1,
3172 // ,,,,,,,,,,
3173 // 1,,1,,1,,1,,1,,1,
3174 // ,,,,,,,,,,
3175 // 1,,1,,1,,1,,1,,1,
3176 // ,,,,,,,,,,
3177 // 1,,1,,1,,1,,1,,1,
3178
3179 // Third pass fills in the blanks
3180 // ResultArr2:
3181 // 1,1,1,1,1,1,1,1,1,1,1,1
3182 // 1,1,1,1,1,1,1,1,1,1,1,1
3183 // 1,1,1,1,1,1,1,1,1,1,1,1
3184 // 1,1,1,1,1,1,1,1,1,1,1,1
3185 // 1,1,1,1,1,1,1,1,1,1,1,1
3186 // 1,1,1,1,1,1,1,1,1,1,1,1
3187 // 1,1,1,1,1,1,1,1,1,1,1,1
3188 // 1,1,1,1,1,1,1,1,1,1,1,1
3189 // 1,1,1,1,1,1,1,1,1,1,1,1
3190 // 1,1,1,1,1,1,1,1,1,1,1,1
3191 // 1,1,1,1,1,1,1,1,1,1,1,1
3192
3193 // X,Y = .
3194 // X+1,y = ^
3195 // X,Y+1 = *
3196 // X+1,Y+1 = #
3197
3198 // Filling in like this;
3199 // .*
3200 // ^#
3201 // 1st .
3202 // 2nd *
3203 // 3rd ^
3204 // 4th #
3205 // on single loop.
3206
3207 float[,] resultarr2 = new float[512, 512];
3208 for (int y = 0; y < WorldExtents.Y; y++)
3209 {
3210 for (int x = 0; x < WorldExtents.X; x++)
3211 {
3212 resultarr2[y * 2, x * 2] = resultarr[y, x];
3213
3214 if (y < WorldExtents.Y)
3215 {
3216 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3217 }
3218 if (x < WorldExtents.X)
3219 {
3220 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3221 }
3222 if (x < WorldExtents.X && y < WorldExtents.Y)
3223 {
3224 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3225 }
3226 }
3227 }
3228
3229 //Flatten out the array
3230 int i = 0;
3231 for (int y = 0; y < 512; y++)
3232 {
3233 for (int x = 0; x < 512; x++)
3234 {
3235 if (resultarr2[y, x] <= 0)
3236 returnarr[i] = 0.0000001f;
3237 else
3238 returnarr[i] = resultarr2[y, x];
3239
3240 i++;
3241 }
3242 }
3243
3244 return returnarr;
3245 }
3246
3247 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3248 {
3249 float[] returnarr = new float[262144];
3250 float[,] resultarr = new float[512,512];
3251
3252 // Filling out the array into its multi-dimensional components
3253 for (int y = 0; y < 256; y++)
3254 {
3255 for (int x = 0; x < 256; x++)
3256 {
3257 resultarr[y, x] = heightMap[y * 256 + x];
3258 }
3259 }
3260
3261 // Resize using interpolation
3262
3263 // This particular way is quick but it only works on a multiple of the original
3264
3265 // The idea behind this method can be described with the following diagrams
3266 // second pass and third pass happen in the same loop really.. just separated
3267 // them to show what this does.
3268
3269 // First Pass
3270 // ResultArr:
3271 // 1,1,1,1,1,1
3272 // 1,1,1,1,1,1
3273 // 1,1,1,1,1,1
3274 // 1,1,1,1,1,1
3275 // 1,1,1,1,1,1
3276 // 1,1,1,1,1,1
3277
3278 // Second Pass
3279 // ResultArr2:
3280 // 1,,1,,1,,1,,1,,1,
3281 // ,,,,,,,,,,
3282 // 1,,1,,1,,1,,1,,1,
3283 // ,,,,,,,,,,
3284 // 1,,1,,1,,1,,1,,1,
3285 // ,,,,,,,,,,
3286 // 1,,1,,1,,1,,1,,1,
3287 // ,,,,,,,,,,
3288 // 1,,1,,1,,1,,1,,1,
3289 // ,,,,,,,,,,
3290 // 1,,1,,1,,1,,1,,1,
3291
3292 // Third pass fills in the blanks
3293 // ResultArr2:
3294 // 1,1,1,1,1,1,1,1,1,1,1,1
3295 // 1,1,1,1,1,1,1,1,1,1,1,1
3296 // 1,1,1,1,1,1,1,1,1,1,1,1
3297 // 1,1,1,1,1,1,1,1,1,1,1,1
3298 // 1,1,1,1,1,1,1,1,1,1,1,1
3299 // 1,1,1,1,1,1,1,1,1,1,1,1
3300 // 1,1,1,1,1,1,1,1,1,1,1,1
3301 // 1,1,1,1,1,1,1,1,1,1,1,1
3302 // 1,1,1,1,1,1,1,1,1,1,1,1
3303 // 1,1,1,1,1,1,1,1,1,1,1,1
3304 // 1,1,1,1,1,1,1,1,1,1,1,1
3305
3306 // X,Y = .
3307 // X+1,y = ^
3308 // X,Y+1 = *
3309 // X+1,Y+1 = #
3310
3311 // Filling in like this;
3312 // .*
3313 // ^#
3314 // 1st .
3315 // 2nd *
3316 // 3rd ^
3317 // 4th #
3318 // on single loop.
3319
3320 float[,] resultarr2 = new float[512,512];
3321 for (int y = 0; y < (int)Constants.RegionSize; y++)
3322 {
3323 for (int x = 0; x < (int)Constants.RegionSize; x++)
3324 {
3325 resultarr2[y*2, x*2] = resultarr[y, x];
3326
3327 if (y < (int)Constants.RegionSize)
3328 {
3329 if (y + 1 < (int)Constants.RegionSize)
3330 {
3331 if (x + 1 < (int)Constants.RegionSize)
3332 {
3333 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3334 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3335 }
3336 else
3337 {
3338 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3339 }
3340 }
3341 else
3342 {
3343 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3344 }
3345 }
3346 if (x < (int)Constants.RegionSize)
3347 {
3348 if (x + 1 < (int)Constants.RegionSize)
3349 {
3350 if (y + 1 < (int)Constants.RegionSize)
3351 {
3352 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3353 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3354 }
3355 else
3356 {
3357 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3358 }
3359 }
3360 else
3361 {
3362 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3363 }
3364 }
3365 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3366 {
3367 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3368 {
3369 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3370 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3371 }
3372 else
3373 {
3374 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3375 }
3376 }
3377 }
3378 }
3379 //Flatten out the array
3380 int i = 0;
3381 for (int y = 0; y < 512; y++)
3382 {
3383 for (int x = 0; x < 512; x++)
3384 {
3385 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3386 {
3387 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3388 resultarr2[y, x] = 0;
3389 }
3390 returnarr[i] = resultarr2[y, x];
3391 i++;
3392 }
3393 }
3394
3395 return returnarr;
3396 }
3397
3398 #endregion
3399
3400 public override void SetTerrain(float[] heightMap)
3401 {
3402 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3403 {
3404 if (m_parentScene is OdeScene)
3405 {
3406 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3407 }
3408 }
3409 else
3410 {
3411 SetTerrain(heightMap, m_worldOffset);
3412 }
3413 }
3414
3415 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3416 {
3417
3418 uint regionsize = (uint) Constants.RegionSize; // visible region size eg. 256(M)
3419
3420 uint heightmapWidth = regionsize + 1; // ODE map size 257 x 257 (Meters) (1 extra
3421 uint heightmapHeight = regionsize + 1;
3422
3423 uint heightmapWidthSamples = (uint)regionsize + 2; // Sample file size, 258 x 258 samples
3424 uint heightmapHeightSamples = (uint)regionsize + 2;
3425
3426 // Array of height samples for ODE
3427 float[] _heightmap;
3428 _heightmap = new float[(heightmapWidthSamples * heightmapHeightSamples)]; // loaded samples 258 x 258
3429
3430 // Other ODE parameters
3431 const float scale = 1.0f;
3432 const float offset = 0.0f;
3433 const float thickness = 2.0f; // Was 0.2f, Larger appears to prevent Av fall-through
3434 const int wrap = 0;
3435
3436 float hfmin = 2000f;
3437 float hfmax = -2000f;
3438 float minele = 0.0f; // Dont allow -ve heights
3439
3440 uint x = 0;
3441 uint y = 0;
3442 uint xx = 0;
3443 uint yy = 0;
3444
3445 // load the height samples array from the heightMap
3446 for ( x = 0; x < heightmapWidthSamples; x++) // 0 to 257
3447 {
3448 for ( y = 0; y < heightmapHeightSamples; y++) // 0 to 257
3449 {
3450 xx = x - 1;
3451 if (xx < 0) xx = 0;
3452 if (xx > (regionsize - 1)) xx = regionsize - 1;
3453
3454 yy = y - 1;
3455 if (yy < 0) yy = 0;
3456 if (yy > (regionsize - 1)) yy = regionsize - 1;
3457 // Input xx = 0 0 1 2 ..... 254 255 255 256 total in
3458 // Output x = 0 1 2 3 ..... 255 256 257 258 total out
3459 float val= heightMap[(yy * regionsize) + xx]; // input from heightMap, <0-255 * 256> <0-255>
3460 if (val < minele) val = minele;
3461 _heightmap[x * (regionsize + 2) + y] = val; // samples output to _heightmap, <0-257 * 258> <0-257>
3462 hfmin = (val < hfmin) ? val : hfmin;
3463 hfmax = (val > hfmax) ? val : hfmax;
3464 }
3465 }
3466
3467 lock (OdeLock)
3468 {
3469 IntPtr GroundGeom = IntPtr.Zero;
3470 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3471 {
3472 RegionTerrain.Remove(pOffset);
3473 if (GroundGeom != IntPtr.Zero)
3474 {
3475 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3476 {
3477 TerrainHeightFieldHeights.Remove(GroundGeom);
3478 }
3479 d.SpaceRemove(space, GroundGeom);
3480 d.GeomDestroy(GroundGeom);
3481 }
3482 }
3483 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3484 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0,
3485 heightmapWidth, heightmapHeight, (int)heightmapWidthSamples,
3486 (int)heightmapHeightSamples, scale, offset, thickness, wrap);
3487 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3488 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3489 if (GroundGeom != IntPtr.Zero)
3490 {
3491 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3492 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3493 }
3494 geom_name_map[GroundGeom] = "Terrain";
3495
3496 d.Matrix3 R = new d.Matrix3();
3497
3498 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3499 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3500 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3501
3502 q1 = q1 * q2;
3503 //q1 = q1 * q3;
3504 Vector3 v3;
3505 float angle;
3506 q1.GetAxisAngle(out v3, out angle);
3507
3508 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3509 d.GeomSetRotation(GroundGeom, ref R);
3510 d.GeomSetPosition(GroundGeom, (pOffset.X + (regionsize * 0.5f)) - 0.5f, (pOffset.Y + (regionsize * 0.5f)) - 0.5f, 0);
3511 IntPtr testGround = IntPtr.Zero;
3512 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3513 {
3514 RegionTerrain.Remove(pOffset);
3515 }
3516 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3517 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3518 }
3519 }
3520
3521 public override void DeleteTerrain()
3522 {
3523 }
3524
3525 public float GetWaterLevel()
3526 {
3527 return waterlevel;
3528 }
3529
3530 public override bool SupportsCombining()
3531 {
3532 return true;
3533 }
3534
3535 public override void UnCombine(PhysicsScene pScene)
3536 {
3537 IntPtr localGround = IntPtr.Zero;
3538// float[] localHeightfield;
3539 bool proceed = false;
3540 List<IntPtr> geomDestroyList = new List<IntPtr>();
3541
3542 lock (OdeLock)
3543 {
3544 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3545 {
3546 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3547 {
3548 if (geom == localGround)
3549 {
3550// localHeightfield = TerrainHeightFieldHeights[geom];
3551 proceed = true;
3552 }
3553 else
3554 {
3555 geomDestroyList.Add(geom);
3556 }
3557 }
3558
3559 if (proceed)
3560 {
3561 m_worldOffset = Vector3.Zero;
3562 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3563 m_parentScene = null;
3564
3565 foreach (IntPtr g in geomDestroyList)
3566 {
3567 // removingHeightField needs to be done or the garbage collector will
3568 // collect the terrain data before we tell ODE to destroy it causing
3569 // memory corruption
3570 if (TerrainHeightFieldHeights.ContainsKey(g))
3571 {
3572// float[] removingHeightField = TerrainHeightFieldHeights[g];
3573 TerrainHeightFieldHeights.Remove(g);
3574
3575 if (RegionTerrain.ContainsKey(g))
3576 {
3577 RegionTerrain.Remove(g);
3578 }
3579
3580 d.GeomDestroy(g);
3581 //removingHeightField = new float[0];
3582 }
3583 }
3584
3585 }
3586 else
3587 {
3588 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3589
3590 }
3591 }
3592 }
3593 }
3594
3595 public override void SetWaterLevel(float baseheight)
3596 {
3597 waterlevel = baseheight;
3598 randomizeWater(waterlevel);
3599 }
3600
3601 public void randomizeWater(float baseheight)
3602 {
3603 const uint heightmapWidth = m_regionWidth + 2;
3604 const uint heightmapHeight = m_regionHeight + 2;
3605 const uint heightmapWidthSamples = m_regionWidth + 2;
3606 const uint heightmapHeightSamples = m_regionHeight + 2;
3607 const float scale = 1.0f;
3608 const float offset = 0.0f;
3609 const float thickness = 2.9f;
3610 const int wrap = 0;
3611
3612 for (int i = 0; i < (258 * 258); i++)
3613 {
3614 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3615 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3616 }
3617
3618 lock (OdeLock)
3619 {
3620 if (WaterGeom != IntPtr.Zero)
3621 {
3622 d.SpaceRemove(space, WaterGeom);
3623 }
3624 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3625 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3626 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3627 offset, thickness, wrap);
3628 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3629 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3630 if (WaterGeom != IntPtr.Zero)
3631 {
3632 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3633 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3634
3635 }
3636 geom_name_map[WaterGeom] = "Water";
3637
3638 d.Matrix3 R = new d.Matrix3();
3639
3640 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3641 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3642 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3643
3644 q1 = q1 * q2;
3645 //q1 = q1 * q3;
3646 Vector3 v3;
3647 float angle;
3648 q1.GetAxisAngle(out v3, out angle);
3649
3650 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3651 d.GeomSetRotation(WaterGeom, ref R);
3652 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3653
3654 }
3655
3656 }
3657
3658 public override void Dispose()
3659 {
3660 m_rayCastManager.Dispose();
3661 m_rayCastManager = null;
3662
3663 lock (OdeLock)
3664 {
3665 lock (_prims)
3666 {
3667 foreach (OdePrim prm in _prims)
3668 {
3669 RemovePrim(prm);
3670 }
3671 }
3672
3673 //foreach (OdeCharacter act in _characters)
3674 //{
3675 //RemoveAvatar(act);
3676 //}
3677 d.WorldDestroy(world);
3678 //d.CloseODE();
3679 }
3680 }
3681 public override Dictionary<uint, float> GetTopColliders()
3682 {
3683 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3684 int cnt = 0;
3685 lock (_prims)
3686 {
3687 foreach (OdePrim prm in _prims)
3688 {
3689 if (prm.CollisionScore > 0)
3690 {
3691 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3692 cnt++;
3693 prm.CollisionScore = 0f;
3694 if (cnt > 25)
3695 {
3696 break;
3697 }
3698 }
3699 }
3700 }
3701 return returncolliders;
3702 }
3703
3704 public override bool SupportsRayCast()
3705 {
3706 return true;
3707 }
3708
3709 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3710 {
3711 if (retMethod != null)
3712 {
3713 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3714 }
3715 }
3716
3717#if USE_DRAWSTUFF
3718 // Keyboard callback
3719 public void command(int cmd)
3720 {
3721 IntPtr geom;
3722 d.Mass mass;
3723 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3724
3725
3726
3727 Char ch = Char.ToLower((Char)cmd);
3728 switch ((Char)ch)
3729 {
3730 case 'w':
3731 try
3732 {
3733 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));
3734
3735 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3736 ds.SetViewpoint(ref xyz, ref hpr);
3737 }
3738 catch (ArgumentException)
3739 { hpr.X = 0; }
3740 break;
3741
3742 case 'a':
3743 hpr.X++;
3744 ds.SetViewpoint(ref xyz, ref hpr);
3745 break;
3746
3747 case 's':
3748 try
3749 {
3750 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));
3751
3752 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3753 ds.SetViewpoint(ref xyz, ref hpr);
3754 }
3755 catch (ArgumentException)
3756 { hpr.X = 0; }
3757 break;
3758 case 'd':
3759 hpr.X--;
3760 ds.SetViewpoint(ref xyz, ref hpr);
3761 break;
3762 case 'r':
3763 xyz.Z++;
3764 ds.SetViewpoint(ref xyz, ref hpr);
3765 break;
3766 case 'f':
3767 xyz.Z--;
3768 ds.SetViewpoint(ref xyz, ref hpr);
3769 break;
3770 case 'e':
3771 xyz.Y++;
3772 ds.SetViewpoint(ref xyz, ref hpr);
3773 break;
3774 case 'q':
3775 xyz.Y--;
3776 ds.SetViewpoint(ref xyz, ref hpr);
3777 break;
3778 }
3779 }
3780
3781 public void step(int pause)
3782 {
3783
3784 ds.SetColor(1.0f, 1.0f, 0.0f);
3785 ds.SetTexture(ds.Texture.Wood);
3786 lock (_prims)
3787 {
3788 foreach (OdePrim prm in _prims)
3789 {
3790 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3791 if (prm.prim_geom != IntPtr.Zero)
3792 {
3793 d.Vector3 pos;
3794 d.GeomCopyPosition(prm.prim_geom, out pos);
3795 //d.BodyCopyPosition(body, out pos);
3796
3797 d.Matrix3 R;
3798 d.GeomCopyRotation(prm.prim_geom, out R);
3799 //d.BodyCopyRotation(body, out R);
3800
3801
3802 d.Vector3 sides = new d.Vector3();
3803 sides.X = prm.Size.X;
3804 sides.Y = prm.Size.Y;
3805 sides.Z = prm.Size.Z;
3806
3807 ds.DrawBox(ref pos, ref R, ref sides);
3808 }
3809 }
3810 }
3811 ds.SetColor(1.0f, 0.0f, 0.0f);
3812 lock (_characters)
3813 {
3814 foreach (OdeCharacter chr in _characters)
3815 {
3816 if (chr.Shell != IntPtr.Zero)
3817 {
3818 IntPtr body = d.GeomGetBody(chr.Shell);
3819
3820 d.Vector3 pos;
3821 d.GeomCopyPosition(chr.Shell, out pos);
3822 //d.BodyCopyPosition(body, out pos);
3823
3824 d.Matrix3 R;
3825 d.GeomCopyRotation(chr.Shell, out R);
3826 //d.BodyCopyRotation(body, out R);
3827
3828 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3829 d.Vector3 sides = new d.Vector3();
3830 sides.X = 0.5f;
3831 sides.Y = 0.5f;
3832 sides.Z = 0.5f;
3833
3834 ds.DrawBox(ref pos, ref R, ref sides);
3835 }
3836 }
3837 }
3838 }
3839
3840 public void start(int unused)
3841 {
3842 ds.SetViewpoint(ref xyz, ref hpr);
3843 }
3844#endif
3845 }
3846}