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