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