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, 1815 insertions, 3340 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
index 7a50c4c..03048a4 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
@@ -25,26 +25,21 @@
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
29//#define SPAM 28//#define SPAM
30 29
31using System; 30using System;
32using System.Collections.Generic; 31using System.Collections.Generic;
33using System.Diagnostics;
34using System.IO;
35using System.Linq;
36using System.Reflection; 32using System.Reflection;
37using System.Runtime.InteropServices; 33using System.Runtime.InteropServices;
38using System.Threading; 34using System.Threading;
35using System.IO;
36using System.Diagnostics;
39using log4net; 37using log4net;
40using Nini.Config; 38using Nini.Config;
41using Ode.NET; 39using OdeAPI;
42using OpenMetaverse;
43#if USE_DRAWSTUFF
44using Drawstuff.NET;
45#endif
46using OpenSim.Framework; 40using OpenSim.Framework;
47using OpenSim.Region.Physics.Manager; 41using OpenSim.Region.Physics.Manager;
42using OpenMetaverse;
48 43
49namespace OpenSim.Region.Physics.OdePlugin 44namespace OpenSim.Region.Physics.OdePlugin
50{ 45{
@@ -55,29 +50,42 @@ namespace OpenSim.Region.Physics.OdePlugin
55 End = 2 50 End = 2
56 } 51 }
57 52
58// public struct sCollisionData 53 public struct sCollisionData
59// { 54 {
60// public uint ColliderLocalId; 55 public uint ColliderLocalId;
61// public uint CollidedWithLocalId; 56 public uint CollidedWithLocalId;
62// public int NumberOfCollisions; 57 public int NumberOfCollisions;
63// public int CollisionType; 58 public int CollisionType;
64// public int StatusIndicator; 59 public int StatusIndicator;
65// public int lastframe; 60 public int lastframe;
66// } 61 }
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
67 69
68 [Flags] 70 [Flags]
69 public enum CollisionCategories : int 71 public enum CollisionCategories : uint
70 { 72 {
71 Disabled = 0, 73 Disabled = 0,
72 Geom = 0x00000001, 74 //by 'things' types
73 Body = 0x00000002, 75 Space = 0x01,
74 Space = 0x00000004, 76 Geom = 0x02, // aka prim/part
75 Character = 0x00000008, 77 Character = 0x04,
76 Land = 0x00000010, 78 Land = 0x08,
77 Water = 0x00000020, 79 Water = 0x010,
78 Wind = 0x00000040, 80
79 Sensor = 0x00000080, 81 // by state
80 Selected = 0x00000100 82 Phantom = 0x01000,
83 VolumeDtc = 0x02000,
84 Selected = 0x04000,
85 NoShape = 0x08000,
86
87
88 All = 0xffffffff
81 } 89 }
82 90
83 /// <summary> 91 /// <summary>
@@ -98,400 +106,213 @@ namespace OpenSim.Region.Physics.OdePlugin
98 /// <summary></summary> 106 /// <summary></summary>
99 Plastic = 5, 107 Plastic = 5,
100 /// <summary></summary> 108 /// <summary></summary>
101 Rubber = 6 109 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
102 } 171 }
103 172
173 public struct ODEchangeitem
174 {
175 public PhysicsActor actor;
176 public OdeCharacter character;
177 public changes what;
178 public Object arg;
179 }
180
104 public class OdeScene : PhysicsScene 181 public class OdeScene : PhysicsScene
105 { 182 {
106 private readonly ILog m_log; 183 private readonly ILog m_log;
107 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>(); 184 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
108 185
109 /// <summary> 186 public bool OdeUbitLib = false;
110 /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances. 187// private int threadid = 0;
111 /// </summary> 188 private Random fluidRandomizer = new Random(Environment.TickCount);
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;
253 189
254 /// <summary> 190 const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce;
255 /// Used in calculating physics frame time dilation 191 const float MaxERP = 0.8f;
256 /// </summary> 192 const float minERP = 0.1f;
257 private int tickCountFrameRun; 193 const float comumContactCFM = 0.0001f;
194
195 float frictionMovementMult = 0.8f;
258 196
259 /// <summary> 197 float TerrainBounce = 0.1f;
260 /// Used in calculating physics frame time dilation 198 float TerrainFriction = 0.3f;
261 /// </summary>
262 private int latertickcount;
263 199
264 private Random fluidRandomizer = new Random(Environment.TickCount); 200 public float AvatarFriction = 0;// 0.9f * 0.5f;
265 201
266 private const uint m_regionWidth = Constants.RegionSize; 202 private const uint m_regionWidth = Constants.RegionSize;
267 private const uint m_regionHeight = Constants.RegionSize; 203 private const uint m_regionHeight = Constants.RegionSize;
268 204
269 private float ODE_STEPSIZE = 0.0178f; 205 public float ODE_STEPSIZE = 0.020f;
270 private float metersInSpace = 29.9f; 206 public float HalfOdeStep = 0.01f;
207 public int odetimestepMS = 20; // rounded
208 private float metersInSpace = 25.6f;
271 private float m_timeDilation = 1.0f; 209 private float m_timeDilation = 1.0f;
272 210
211 private DateTime m_lastframe;
212 private DateTime m_lastMeshExpire;
213
273 public float gravityx = 0f; 214 public float gravityx = 0f;
274 public float gravityy = 0f; 215 public float gravityy = 0f;
275 public float gravityz = -9.8f; 216 public float gravityz = -9.8f;
276 217
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
287 private float waterlevel = 0f; 218 private float waterlevel = 0f;
288 private int framecount = 0; 219 private int framecount = 0;
289 //private int m_returncollisions = 10;
290
291 private readonly IntPtr contactgroup;
292
293 internal IntPtr WaterGeom;
294 220
295 private float nmTerrainContactFriction = 255.0f; 221 private int m_meshExpireCntr;
296 private float nmTerrainContactBounce = 0.1f;
297 private float nmTerrainContactERP = 0.1025f;
298 222
299 private float mTerrainContactFriction = 75f; 223// private IntPtr WaterGeom = IntPtr.Zero;
300 private float mTerrainContactBounce = 0.1f; 224// private IntPtr WaterHeightmapData = IntPtr.Zero;
301 private float mTerrainContactERP = 0.05025f; 225// private GCHandle WaterMapHandler = new GCHandle();
302 226
303 private float nmAvatarObjectContactFriction = 250f; 227 public float avPIDD = 2200f; // make it visible
304 private float nmAvatarObjectContactBounce = 0.1f; 228 public float avPIDP = 900f; // make it visible
305
306 private float mAvatarObjectContactFriction = 75f;
307 private float mAvatarObjectContactBounce = 0.1f;
308
309 private float avPIDD = 3200f;
310 private float avPIDP = 1400f;
311 private float avCapRadius = 0.37f; 229 private float avCapRadius = 0.37f;
312 private float avStandupTensor = 2000000f; 230 private float avDensity = 3f;
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;
324 private float avMovementDivisorWalk = 1.3f; 231 private float avMovementDivisorWalk = 1.3f;
325 private float avMovementDivisorRun = 0.8f; 232 private float avMovementDivisorRun = 0.8f;
326 private float minimumGroundFlightOffset = 3f; 233 private float minimumGroundFlightOffset = 3f;
327 public float maximumMassObject = 10000.01f; 234 public float maximumMassObject = 10000.01f;
328 235
329 public bool meshSculptedPrim = true;
330 public bool forceSimplePrimMeshing = false;
331
332 public float meshSculptLOD = 32;
333 public float MeshSculptphysicalLOD = 16;
334 236
335 public float geomDefaultDensity = 10.000006836f; 237 public float geomDefaultDensity = 10.000006836f;
336 238
337 public int geomContactPointsStartthrottle = 3; 239 public int geomContactPointsStartthrottle = 3;
338 public int geomUpdatesPerThrottledUpdate = 15; 240 public int geomUpdatesPerThrottledUpdate = 15;
339 private const int avatarExpectedContacts = 3;
340 241
341 public float bodyPIDD = 35f; 242 public float bodyPIDD = 35f;
342 public float bodyPIDG = 25; 243 public float bodyPIDG = 25;
343 244
344 public int geomCrossingFailuresBeforeOutofbounds = 5; 245// public int geomCrossingFailuresBeforeOutofbounds = 6;
345
346 public float bodyMotorJointMaxforceTensor = 2;
347 246
348 public int bodyFramesAutoDisable = 20; 247 public int bodyFramesAutoDisable = 5;
349 248
350 private float[] _watermap;
351 private bool m_filterCollisions = true;
352 249
353 private d.NearCallback nearCallback; 250 private d.NearCallback nearCallback;
354 public d.TriCallback triCallback;
355 public d.TriArrayCallback triArrayCallback;
356 251
357 /// <summary> 252 private HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
358 /// Avatars in the physics scene. 253 private HashSet<OdePrim> _prims = new HashSet<OdePrim>();
359 /// </summary> 254 private HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
360 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>(); 255 private HashSet<OdePrim> _activegroups = new HashSet<OdePrim>();
361 256
362 /// <summary> 257 public OpenSim.Framework.LocklessQueue<ODEchangeitem> ChangesQueue = new OpenSim.Framework.LocklessQueue<ODEchangeitem>();
363 /// Prims in the physics scene.
364 /// </summary>
365 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
366 258
367 /// <summary> 259 /// <summary>
368 /// Prims in the physics scene that are subject to physics, not just collisions. 260 /// A list of actors that should receive collision events.
369 /// </summary> 261 /// </summary>
370 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>(); 262 private List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
371 263 private List<PhysicsActor> _collisionEventPrimRemove = new List<PhysicsActor>();
372 /// <summary> 264
373 /// Prims that the simulator has created/deleted/updated and so need updating in ODE. 265 private HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
374 /// </summary> 266// public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
375 private readonly HashSet<OdePrim> _taintedPrims = new HashSet<OdePrim>(); 267 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
376
377 /// <summary>
378 /// Record a character that has taints to be processed.
379 /// </summary>
380 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
381 268
382 /// <summary> 269 private float contactsurfacelayer = 0.002f;
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>();
386 270
387 /// <summary> 271 private int contactsPerCollision = 80;
388 /// A dictionary of actors that should receive collision events. 272 internal IntPtr ContactgeomsArray = IntPtr.Zero;
389 /// </summary> 273 private IntPtr GlobalContactsArray = IntPtr.Zero;
390 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActors = new Dictionary<uint, PhysicsActor>();
391 274
392 /// <summary> 275 const int maxContactsbeforedeath = 4000;
393 /// A dictionary of collision event changes that are waiting to be processed. 276 private volatile int m_global_contactcount = 0;
394 /// </summary>
395 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActorsChanges = new Dictionary<uint, PhysicsActor>();
396 277
397 /// <summary> 278 private IntPtr contactgroup;
398 /// Maps a unique geometry id (a memory location) to a physics actor name.
399 /// </summary>
400 /// <remarks>
401 /// Only actors participating in collisions have geometries. This has to be maintained separately from
402 /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own
403 /// apart from the singleton PANull
404 /// </remarks>
405 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
406 279
407 /// <summary> 280 public ContactData[] m_materialContactsData = new ContactData[8];
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 281
415 /// <summary> 282 private Dictionary<Vector3, IntPtr> RegionTerrain = new Dictionary<Vector3, IntPtr>();
416 /// Defects list to remove characters that no longer have finite positions due to some other bug. 283 private Dictionary<IntPtr, float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
417 /// </summary> 284 private Dictionary<IntPtr, GCHandle> TerrainHeightFieldHeightsHandlers = new Dictionary<IntPtr, GCHandle>();
418 /// <remarks> 285
419 /// Used repeatedly in Simulate() but initialized once here. 286 private int m_physicsiterations = 10;
420 /// </remarks> 287 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
421 private readonly List<OdeCharacter> defects = new List<OdeCharacter>(); 288// private PhysicsActor PANull = new NullPhysicsActor();
289 private float step_time = 0.0f;
422 290
423 private bool m_NINJA_physics_joints_enabled = false; 291 public IntPtr world;
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;
427 292
428 /// <summary>
429 /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
430 /// </summary>
431 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>();
432 293
433 /// <summary> 294 // split the spaces acording to contents type
434 /// can lock for longer. accessed only by OdeScene. 295 // ActiveSpace contains characters and active prims
435 /// </summary> 296 // StaticSpace contains land and other that is mostly static in enviroment
436 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); 297 // this can contain subspaces, like the grid in staticspace
298 // as now space only contains this 2 top spaces
437 299
438 /// <summary> 300 public IntPtr TopSpace; // the global space
439 /// can lock for longer. accessed only by OdeScene. 301 public IntPtr ActiveSpace; // space for active prims
440 /// </summary> 302 public IntPtr StaticSpace; // space for the static things around
441 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); 303 public IntPtr GroundSpace; // space for ground
442 304
443 /// <summary> 305 // some speedup variables
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 306 private int spaceGridMaxX;
445 /// </summary> 307 private int spaceGridMaxY;
446 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); 308 private float spacesPerMeter;
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;
488 309
489 /// <summary> 310 // split static geometry collision into a grid as before
490 /// Used to lock the entire physics scene. Locked during the main part of Simulate() 311 private IntPtr[,] staticPrimspace;
491 /// </summary> 312 private IntPtr[] staticPrimspaceOffRegion;
492 internal Object OdeLock = new Object();
493 313
494 private bool _worldInitialized = false; 314 public Object OdeLock;
315 public static Object SimulationLock;
495 316
496 public IMesher mesher; 317 public IMesher mesher;
497 318
@@ -501,461 +322,340 @@ namespace OpenSim.Region.Physics.OdePlugin
501 public int physics_logging_interval = 0; 322 public int physics_logging_interval = 0;
502 public bool physics_logging_append_existing_logfile = false; 323 public bool physics_logging_append_existing_logfile = false;
503 324
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
515 private Vector3 m_worldOffset = Vector3.Zero; 325 private Vector3 m_worldOffset = Vector3.Zero;
516 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); 326 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
517 private PhysicsScene m_parentScene = null; 327 private PhysicsScene m_parentScene = null;
518 328
519 private ODERayCastRequestManager m_rayCastManager; 329 private ODERayCastRequestManager m_rayCastManager;
330 public ODEMeshWorker m_meshWorker;
331
332/* maybe needed if ode uses tls
333 private void checkThread()
334 {
520 335
336 int th = Thread.CurrentThread.ManagedThreadId;
337 if(th != threadid)
338 {
339 threadid = th;
340 d.AllocateODEDataForThread(~0U);
341 }
342 }
343 */
521 /// <summary> 344 /// <summary>
522 /// Initiailizes the scene 345 /// Initiailizes the scene
523 /// Sets many properties that ODE requires to be stable 346 /// Sets many properties that ODE requires to be stable
524 /// These settings need to be tweaked 'exactly' right or weird stuff happens. 347 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
525 /// </summary> 348 /// </summary>
526 /// <param value="name">Name of the scene. Useful in debug messages.</param> 349 public OdeScene(string sceneIdentifier)
527 public OdeScene(string name) 350 {
528 { 351 m_log
529 m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name); 352 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
530 353
531 Name = name; 354// checkThread();
355 Name = sceneIdentifier;
356
357 OdeLock = new Object();
358 SimulationLock = new Object();
532 359
533 nearCallback = near; 360 nearCallback = near;
534 triCallback = TriCallback; 361
535 triArrayCallback = TriArrayCallback;
536 m_rayCastManager = new ODERayCastRequestManager(this); 362 m_rayCastManager = new ODERayCastRequestManager(this);
363
537 364
538 // Create the world and the first space 365 lock (OdeLock)
539 world = d.WorldCreate(); 366 {
540 space = d.HashSpaceCreate(IntPtr.Zero); 367 // Create the world and the first space
368 try
369 {
370 world = d.WorldCreate();
371 TopSpace = d.HashSpaceCreate(IntPtr.Zero);
541 372
542 contactgroup = d.JointGroupCreate(0); 373 // now the major subspaces
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 }
543 382
544 d.WorldSetAutoDisableFlag(world, false); 383 d.HashSpaceSetLevels(TopSpace, -2, 8);
384 d.HashSpaceSetLevels(ActiveSpace, -2, 8);
385 d.HashSpaceSetLevels(StaticSpace, -2, 8);
386 d.HashSpaceSetLevels(GroundSpace, 0, 8);
545 387
546 #if USE_DRAWSTUFF 388 // demote to second level
547 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization)); 389 d.SpaceSetSublevel(ActiveSpace, 1);
548 viewthread.Start(); 390 d.SpaceSetSublevel(StaticSpace, 1);
549 #endif 391 d.SpaceSetSublevel(GroundSpace, 1);
550 392
551 _watermap = new float[258 * 258]; 393 d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space |
394 CollisionCategories.Geom |
395 CollisionCategories.Character |
396 CollisionCategories.Phantom |
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);
552 408
553 // Zero out the prim spaces array (we split our space into smaller spaces so 409 d.GeomSetCategoryBits(GroundSpace, (uint)(CollisionCategories.Land));
554 // we can hit test less. 410 d.GeomSetCollideBits(GroundSpace, 0);
555 }
556 411
557#if USE_DRAWSTUFF 412 contactgroup = d.JointGroupCreate(0);
558 public void startvisualization(object o) 413 //contactgroup
559 { 414
560 ds.Functions fn; 415 d.WorldSetAutoDisableFlag(world, false);
561 fn.version = ds.VERSION; 416 }
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);
569 } 417 }
570#endif
571 418
572 // Initialize the mesh plugin 419 // Initialize the mesh plugin
420// public override void Initialise(IMesher meshmerizer, IConfigSource config, RegionInfo region )
573 public override void Initialise(IMesher meshmerizer, IConfigSource config) 421 public override void Initialise(IMesher meshmerizer, IConfigSource config)
574 { 422 {
575 InitializeExtraStats(); 423// checkThread();
576
577 mesher = meshmerizer; 424 mesher = meshmerizer;
578 m_config = config; 425 m_config = config;
579 // Defaults
580 426
581 if (Environment.OSVersion.Platform == PlatformID.Unix) 427 string ode_config = d.GetConfiguration();
428 if (ode_config != null && ode_config != "")
582 { 429 {
583 avPIDD = 3200.0f; 430 m_log.WarnFormat("ODE configuration: {0}", ode_config);
584 avPIDP = 1400.0f; 431
585 avStandupTensor = 2000000f; 432 if (ode_config.Contains("ODE_Ubit"))
586 } 433 {
587 else 434 OdeUbitLib = true;
588 { 435 }
589 avPIDD = 2200.0f;
590 avPIDP = 900.0f;
591 avStandupTensor = 550000f;
592 } 436 }
593 437
438 /*
439 if (region != null)
440 {
441 WorldExtents.X = region.RegionSizeX;
442 WorldExtents.Y = region.RegionSizeY;
443 }
444 */
445
446 // Defaults
447
594 int contactsPerCollision = 80; 448 int contactsPerCollision = 80;
595 449
450 IConfig physicsconfig = null;
451
596 if (m_config != null) 452 if (m_config != null)
597 { 453 {
598 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; 454 physicsconfig = m_config.Configs["ODEPhysicsSettings"];
599 if (physicsconfig != null) 455 if (physicsconfig != null)
600 { 456 {
601 CollectStats = physicsconfig.GetBoolean("collect_stats", false); 457 gravityx = physicsconfig.GetFloat("world_gravityx", gravityx);
602 458 gravityy = physicsconfig.GetFloat("world_gravityy", gravityy);
603 gravityx = physicsconfig.GetFloat("world_gravityx", 0f); 459 gravityz = physicsconfig.GetFloat("world_gravityz", gravityz);
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);
628 460
629 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f); 461 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", metersInSpace);
630 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
631 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
632 462
633 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f); 463 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", contactsurfacelayer);
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);
638 464
639 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE); 465 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE);
640 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10); 466 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", m_physicsiterations);
641 467
642 avDensity = physicsconfig.GetFloat("av_density", 80f); 468 avDensity = physicsconfig.GetFloat("av_density", avDensity);
643// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f); 469 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", avMovementDivisorWalk);
644 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); 470 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", avMovementDivisorRun);
645 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); 471 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", avCapRadius);
646 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
647 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
648 472
649 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); 473 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", contactsPerCollision);
650 474
651 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5); 475 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
652 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); 476 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
653 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); 477// 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);
660 478
661 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); 479 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", geomDefaultDensity);
662 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true); 480 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", bodyFramesAutoDisable);
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 }
681 481
682 physics_logging = physicsconfig.GetBoolean("physics_logging", false); 482 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
683 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); 483 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
684 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false); 484 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
685 485
686 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); 486 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", minimumGroundFlightOffset);
687 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); 487 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", maximumMassObject);
688 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
689 } 488 }
690 } 489 }
691 490
692 contacts = new d.ContactGeom[contactsPerCollision]; 491 m_meshWorker = new ODEMeshWorker(this, m_log, meshmerizer, physicsconfig);
693
694 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
695
696 // Centeral contact friction and bounce
697 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
698 // an avatar falls through in Z but not in X or Y when walking on a prim.
699 contact.surface.mode |= d.ContactFlags.SoftERP;
700 contact.surface.mu = nmAvatarObjectContactFriction;
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;
732 492
733 /* 493 HalfOdeStep = ODE_STEPSIZE * 0.5f;
734 <summary></summary> 494 odetimestepMS = (int)(1000.0f * ODE_STEPSIZE +0.5f);
735 Stone = 0,
736 /// <summary></summary>
737 Metal = 1,
738 /// <summary></summary>
739 Glass = 2,
740 /// <summary></summary>
741 Wood = 3,
742 /// <summary></summary>
743 Flesh = 4,
744 /// <summary></summary>
745 Plastic = 5,
746 /// <summary></summary>
747 Rubber = 6
748 */
749 495
750 m_materialContacts = new d.Contact[7,2]; 496 ContactgeomsArray = Marshal.AllocHGlobal(contactsPerCollision * d.ContactGeom.unmanagedSizeOf);
751 497 GlobalContactsArray = GlobalContactsArray = Marshal.AllocHGlobal(maxContactsbeforedeath * d.Contact.unmanagedSizeOf);
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;
786 498
787 /* 499 m_materialContactsData[(int)Material.Stone].mu = 0.8f;
788 private float nmAvatarObjectContactFriction = 250f; 500 m_materialContactsData[(int)Material.Stone].bounce = 0.4f;
789 private float nmAvatarObjectContactBounce = 0.1f;
790 501
791 private float mAvatarObjectContactFriction = 75f; 502 m_materialContactsData[(int)Material.Metal].mu = 0.3f;
792 private float mAvatarObjectContactBounce = 0.1f; 503 m_materialContactsData[(int)Material.Metal].bounce = 0.4f;
793 */ 504
794 m_materialContacts[(int)Material.Glass, 1] = new d.Contact(); 505 m_materialContactsData[(int)Material.Glass].mu = 0.2f;
795 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP; 506 m_materialContactsData[(int)Material.Glass].bounce = 0.7f;
796 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f; 507
797 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f; 508 m_materialContactsData[(int)Material.Wood].mu = 0.6f;
798 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f; 509 m_materialContactsData[(int)Material.Wood].bounce = 0.5f;
799 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f; 510
800 511 m_materialContactsData[(int)Material.Flesh].mu = 0.9f;
801 m_materialContacts[(int)Material.Wood, 0] = new d.Contact(); 512 m_materialContactsData[(int)Material.Flesh].bounce = 0.3f;
802 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP; 513
803 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction; 514 m_materialContactsData[(int)Material.Plastic].mu = 0.4f;
804 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce; 515 m_materialContactsData[(int)Material.Plastic].bounce = 0.7f;
805 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f; 516
806 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f; 517 m_materialContactsData[(int)Material.Rubber].mu = 0.9f;
807 518 m_materialContactsData[(int)Material.Rubber].bounce = 0.95f;
808 m_materialContacts[(int)Material.Wood, 1] = new d.Contact(); 519
809 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP; 520 m_materialContactsData[(int)Material.light].mu = 0.0f;
810 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction; 521 m_materialContactsData[(int)Material.light].bounce = 0.0f;
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);
858 522
859 // Set the gravity,, don't disable things automatically (we set it explicitly on some things) 523 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
860 524
861 d.WorldSetGravity(world, gravityx, gravityy, gravityz); 525 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
862 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); 526 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
863 527
864 d.WorldSetLinearDamping(world, 256f); 528 d.WorldSetLinearDamping(world, 0.002f);
865 d.WorldSetAngularDamping(world, 256f); 529 d.WorldSetAngularDamping(world, 0.002f);
866 d.WorldSetAngularDampingThreshold(world, 256f); 530 d.WorldSetAngularDampingThreshold(world, 0f);
867 d.WorldSetLinearDampingThreshold(world, 256f); 531 d.WorldSetLinearDampingThreshold(world, 0f);
868 d.WorldSetMaxAngularSpeed(world, 256f); 532 d.WorldSetMaxAngularSpeed(world, 100f);
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
869 537
870 // Set how many steps we go without running collision testing 538 // Set how many steps we go without running collision testing
871 // This is in addition to the step size. 539 // This is in addition to the step size.
872 // Essentially Steps * m_physicsiterations 540 // Essentially Steps * m_physicsiterations
873 d.WorldSetQuickStepNumIterations(world, m_physicsiterations); 541 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
874 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
875 542
876 for (int i = 0; i < staticPrimspace.GetLength(0); i++) 543 d.WorldSetContactMaxCorrectingVel(world, 60.0f);
877 { 544
878 for (int j = 0; j < staticPrimspace.GetLength(1); j++) 545 spacesPerMeter = 1 / metersInSpace;
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++)
879 { 557 {
880 staticPrimspace[i, j] = IntPtr.Zero; 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 {
583 newspace = d.HashSpaceCreate(StaticSpace);
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;
881 } 598 }
882 }
883 599
884 _worldInitialized = true; 600 m_lastframe = DateTime.UtcNow;
601 m_lastMeshExpire = m_lastframe;
885 } 602 }
886 603
887// internal void waitForSpaceUnlock(IntPtr space) 604 internal void waitForSpaceUnlock(IntPtr space)
888// { 605 {
889// //if (space != IntPtr.Zero) 606 //if (space != IntPtr.Zero)
890// //while (d.SpaceLockQuery(space)) { } // Wait and do nothing 607 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
891// } 608 }
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// }
902 609
903 #region Collision Detection 610 #region Collision Detection
904 611
905 /// <summary> 612 // sets a global contact for a joint for contactgeom , and base contact description)
906 /// Collides two geometries. 613
907 /// </summary> 614 private IntPtr CreateContacJoint(ref d.ContactGeom contactGeom, float mu, float bounce, float cfm, float erpscale, float dscale)
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)
916 { 615 {
917 int count; 616 if (GlobalContactsArray == IntPtr.Zero || m_global_contactcount >= maxContactsbeforedeath)
617 return IntPtr.Zero;
918 618
919 lock (OdeScene.UniversalColliderSyncObject) 619 float erp = contactGeom.depth;
920 { 620 erp *= erpscale;
921 // We do this inside the lock so that we don't count any delay in acquiring it 621 if (erp < minERP)
922 if (CollectStats) 622 erp = minERP;
923 m_nativeCollisionStartTick = Util.EnvironmentTickCount(); 623 else if (erp > MaxERP)
624 erp = MaxERP;
924 625
925 count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize); 626 float depth = contactGeom.depth * dscale;
926 } 627 if (depth > 0.5f)
628 depth = 0.5f;
629
630 d.Contact newcontact = new d.Contact();
631 newcontact.geom.depth = depth;
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;
927 638
928 // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably 639 // this needs bounce also
929 // negligable 640 newcontact.surface.mode = comumContactFlags;
930 if (CollectStats) 641 newcontact.surface.mu = mu;
931 m_stats[ODENativeGeomCollisionFrameMsStatName] 642 newcontact.surface.bounce = bounce;
932 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); 643 newcontact.surface.soft_cfm = cfm;
644 newcontact.surface.soft_erp = erp;
933 645
934 return count; 646 IntPtr contact = new IntPtr(GlobalContactsArray.ToInt64() + (Int64)(m_global_contactcount * d.Contact.unmanagedSizeOf));
647 Marshal.StructureToPtr(newcontact, contact, true);
648 return d.JointCreateContactPtr(world, contactgroup, contact);
935 } 649 }
936 650
937 /// <summary> 651 private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom)
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)
944 { 652 {
945 if (CollectStats) 653 if (ContactgeomsArray == IntPtr.Zero || index >= contactsPerCollision)
946 { 654 return false;
947 m_inCollisionTiming = true;
948 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
949 }
950
951 d.SpaceCollide2(space1, space2, data, nearCallback);
952 655
953 if (CollectStats && m_inCollisionTiming) 656 IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf));
954 { 657 newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom));
955 m_stats[ODENativeSpaceCollisionFrameMsStatName] 658 return true;
956 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
957 m_inCollisionTiming = false;
958 }
959 } 659 }
960 660
961 /// <summary> 661 /// <summary>
@@ -964,76 +664,50 @@ namespace OpenSim.Region.Physics.OdePlugin
964 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param> 664 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
965 /// <param name="g1">a geometry or space</param> 665 /// <param name="g1">a geometry or space</param>
966 /// <param name="g2">another geometry or space</param> 666 /// <param name="g2">another geometry or space</param>
667 ///
668
967 private void near(IntPtr space, IntPtr g1, IntPtr g2) 669 private void near(IntPtr space, IntPtr g1, IntPtr g2)
968 { 670 {
969 if (CollectStats && m_inCollisionTiming)
970 {
971 m_stats[ODENativeSpaceCollisionFrameMsStatName]
972 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
973 m_inCollisionTiming = false;
974 }
975
976// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
977 // no lock here! It's invoked from within Simulate(), which is thread-locked 671 // no lock here! It's invoked from within Simulate(), which is thread-locked
978 672
673 if (m_global_contactcount >= maxContactsbeforedeath)
674 return;
675
979 // Test if we're colliding a geom with a space. 676 // Test if we're colliding a geom with a space.
980 // If so we have to drill down into the space recursively 677 // If so we have to drill down into the space recursively
981 678
679 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
680 return;
681
982 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) 682 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
983 { 683 {
984 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
985 return;
986
987 // Separating static prim geometry spaces.
988 // We'll be calling near recursivly if one 684 // We'll be calling near recursivly if one
989 // of them is a space to find all of the 685 // of them is a space to find all of the
990 // contact points in the space 686 // contact points in the space
991 try 687 try
992 { 688 {
993 CollideSpaces(g1, g2, IntPtr.Zero); 689 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
994 } 690 }
995 catch (AccessViolationException) 691 catch (AccessViolationException)
996 { 692 {
997 m_log.Error("[ODE SCENE]: Unable to collide test a space"); 693 m_log.Warn("[PHYSICS]: Unable to collide test a space");
998 return; 694 return;
999 } 695 }
1000 //Colliding a space or a geom with a space or a geom. so drill down 696 //here one should check collisions of geoms inside a space
1001 697 // but on each space we only should have geoms that not colide amoung each other
1002 //Collide all geoms in each space.. 698 // so we don't dig inside spaces
1003 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
1004 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
1005 return; 699 return;
1006 } 700 }
1007 701
1008 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) 702 // get geom bodies to check if we already a joint contact
1009 return; 703 // guess this shouldn't happen now
1010
1011 IntPtr b1 = d.GeomGetBody(g1); 704 IntPtr b1 = d.GeomGetBody(g1);
1012 IntPtr b2 = d.GeomGetBody(g2); 705 IntPtr b2 = d.GeomGetBody(g2);
1013 706
1014 // d.GeomClassID id = d.GeomGetClass(g1); 707 // d.GeomClassID id = d.GeomGetClass(g1);
1015 708
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
1034 // Figure out how many contact points we have 709 // Figure out how many contact points we have
1035 int count = 0; 710 int count = 0;
1036
1037 try 711 try
1038 { 712 {
1039 // Colliding Geom To Geom 713 // Colliding Geom To Geom
@@ -1045,914 +719,611 @@ namespace OpenSim.Region.Physics.OdePlugin
1045 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) 719 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
1046 return; 720 return;
1047 721
1048 count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); 722// debug
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
1049 746
1050 // All code after this is only relevant if we have any collisions
1051 if (count <= 0)
1052 return;
1053 747
1054 if (count > contacts.Length) 748 if(d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc ||
1055 m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); 749 d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc)
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);
1056 } 760 }
1057 catch (SEHException) 761 catch (SEHException)
1058 { 762 {
1059 m_log.Error( 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.");
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."); 764// ode.drelease(world);
1061 base.TriggerPhysicsBasedRestart(); 765 base.TriggerPhysicsBasedRestart();
1062 } 766 }
1063 catch (Exception e) 767 catch (Exception e)
1064 { 768 {
1065 m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message); 769 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
1066 return; 770 return;
1067 } 771 }
1068 772
773 // contacts done
774 if (count == 0)
775 return;
776
777 // try get physical actors
1069 PhysicsActor p1; 778 PhysicsActor p1;
1070 PhysicsActor p2; 779 PhysicsActor p2;
1071 780
1072 p1ExpectedPoints = 0;
1073 p2ExpectedPoints = 0;
1074
1075 if (!actor_name_map.TryGetValue(g1, out p1)) 781 if (!actor_name_map.TryGetValue(g1, out p1))
1076 { 782 {
1077 p1 = PANull; 783 m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 1");
784 return;
1078 } 785 }
1079 786
1080 if (!actor_name_map.TryGetValue(g2, out p2)) 787 if (!actor_name_map.TryGetValue(g2, out p2))
1081 { 788 {
1082 p2 = PANull; 789 m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2");
790 return;
1083 } 791 }
1084 792
1085 ContactPoint maxDepthContact = new ContactPoint(); 793 // update actors collision score
1086 if (p1.CollisionScore + count >= float.MaxValue) 794 if (p1.CollisionScore >= float.MaxValue - count)
1087 p1.CollisionScore = 0; 795 p1.CollisionScore = 0;
1088 p1.CollisionScore += count; 796 p1.CollisionScore += count;
1089 797
1090 if (p2.CollisionScore + count >= float.MaxValue) 798 if (p2.CollisionScore >= float.MaxValue - count)
1091 p2.CollisionScore = 0; 799 p2.CollisionScore = 0;
1092 p2.CollisionScore += count; 800 p2.CollisionScore += count;
1093 801
1094 for (int i = 0; i < count; i++) 802 // get first contact
1095 { 803 d.ContactGeom curContact = new d.ContactGeom();
1096 d.ContactGeom curContact = contacts[i]; 804 if (!GetCurContactGeom(0, ref curContact))
1097 805 return;
1098 if (curContact.depth > maxDepthContact.PenetrationDepth) 806 // for now it's the one with max depth
1099 { 807 ContactPoint maxDepthContact = new ContactPoint(
1100 maxDepthContact = new ContactPoint(
1101 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), 808 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
1102 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), 809 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
1103 curContact.depth 810 curContact.depth
1104 ); 811 );
1105 } 812 // do volume detection case
1106 813 if (
1107 //m_log.Warn("[CCOUNT]: " + count); 814 (p1.IsVolumeDtc || p2.IsVolumeDtc))
1108 IntPtr joint; 815 {
1109 // If we're colliding with terrain, use 'TerrainContact' instead of contact. 816 collision_accounting_events(p1, p2, maxDepthContact);
1110 // allows us to have different settings 817 return;
1111 818 }
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
1116 819
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)); 820 // big messy collision analises
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)
1127 821
1128 switch (p1.PhysicsActorType) 822 Vector3 normoverride = Vector3.Zero; //damm c#
1129 {
1130 case (int)ActorTypes.Agent:
1131 p1ExpectedPoints = avatarExpectedContacts;
1132 p2.CollidingObj = true;
1133 break;
1134 case (int)ActorTypes.Prim:
1135 if (p1 != null && p1 is OdePrim)
1136 p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
1137 823
1138 if (p2.Velocity.LengthSquared() > 0.0f) 824 float mu = 0;
1139 p2.CollidingObj = true; 825 float bounce = 0;
1140 break; 826 float cfm = 0.0001f;
1141 case (int)ActorTypes.Unknown: 827 float erpscale = 1.0f;
1142 p2.CollidingGround = true; 828 float dscale = 1.0f;
1143 break; 829 bool IgnoreNegSides = false;
1144 default:
1145 p2.CollidingGround = true;
1146 break;
1147 }
1148 830
1149 // we don't want prim or avatar to explode 831 ContactData contactdata1 = new ContactData(0, 0, false);
832 ContactData contactdata2 = new ContactData(0, 0, false);
1150 833
1151 #region InterPenetration Handling - Unintended physics explosions 834 bool dop1foot = false;
1152# region disabled code1 835 bool dop2foot = false;
836 bool ignore = false;
837 bool AvanormOverride = false;
1153 838
1154 if (curContact.depth >= 0.08f) 839 switch (p1.PhysicsActorType)
1155 { 840 {
1156 //This is disabled at the moment only because it needs more tweaking 841 case (int)ActorTypes.Agent:
1157 //It will eventually be uncommented
1158 /*
1159 if (contact.depth >= 1.00f)
1160 { 842 {
1161 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString()); 843 AvanormOverride = true;
1162 } 844 Vector3 tmp = p2.Position - p1.Position;
845 normoverride = p2.Velocity - p1.Velocity;
846 mu = normoverride.LengthSquared();
1163 847
1164 //If you interpenetrate a prim with an agent 848 if (mu > 1e-6)
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)
1174 { 849 {
1175 p2.CollidingObj = true; 850 mu = 1.0f / (float)Math.Sqrt(mu);
1176 contact.depth = 0.003f; 851 normoverride *= mu;
1177 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f); 852 mu = Vector3.Dot(tmp, normoverride);
1178 OdeCharacter character = (OdeCharacter) p2; 853 if (mu > 0)
1179 character.SetPidStatus(true); 854 normoverride *= -1;
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
1182 } 855 }
1183 else 856 else
1184 { 857 {
1185 858 tmp.Normalize();
1186 //contact.depth = 0.0000000f; 859 normoverride = -tmp;
1187 } 860 }
1188 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1189 {
1190 861
1191 p1.CollidingObj = true; 862 switch (p2.PhysicsActorType)
1192 contact.depth = 0.003f;
1193 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
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));
1195 OdeCharacter character = (OdeCharacter)p1;
1196 character.SetPidStatus(true);
1197 }
1198 else
1199 { 863 {
864 case (int)ActorTypes.Agent:
865 p1.CollidingObj = true;
866 p2.CollidingObj = true;
867 break;
868
869 case (int)ActorTypes.Prim:
870 if (p2.Velocity.LengthSquared() > 0.0f)
871 p2.CollidingObj = true;
872 dop1foot = true;
873 break;
1200 874
1201 //contact.depth = 0.0000000f; 875 default:
876 ignore = true; // avatar to terrain and water ignored
877 break;
1202 } 878 }
1203 879 break;
1204
1205
1206 }
1207*/
1208 // If you interpenetrate a prim with another prim
1209 /*
1210 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
1211 {
1212 #region disabledcode2
1213 //OdePrim op1 = (OdePrim)p1;
1214 //OdePrim op2 = (OdePrim)p2;
1215 //op1.m_collisionscore++;
1216 //op2.m_collisionscore++;
1217
1218 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
1219 //{
1220 //op1.m_taintdisable = true;
1221 //AddPhysicsActorTaint(p1);
1222 //op2.m_taintdisable = true;
1223 //AddPhysicsActorTaint(p2);
1224 //}
1225
1226 //if (contact.depth >= 0.25f)
1227 //{
1228 // Don't collide, one or both prim will expld.
1229
1230 //op1.m_interpenetrationcount++;
1231 //op2.m_interpenetrationcount++;
1232 //interpenetrations_before_disable = 200;
1233 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
1234 //{
1235 //op1.m_taintdisable = true;
1236 //AddPhysicsActorTaint(p1);
1237 //}
1238 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
1239 //{
1240 // op2.m_taintdisable = true;
1241 //AddPhysicsActorTaint(p2);
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 } 880 }
1254 */ 881
1255#endregion 882 case (int)ActorTypes.Prim:
1256 if (curContact.depth >= 1.00f) 883 switch (p2.PhysicsActorType)
1257 { 884 {
1258 //m_log.Info("[P]: " + contact.depth.ToString()); 885 case (int)ActorTypes.Agent:
1259 if ((p2.PhysicsActorType == (int) ActorTypes.Agent && 886 AvanormOverride = true;
1260 p1.PhysicsActorType == (int) ActorTypes.Unknown) || 887
1261 (p1.PhysicsActorType == (int) ActorTypes.Agent && 888 Vector3 tmp = p2.Position - p1.Position;
1262 p2.PhysicsActorType == (int) ActorTypes.Unknown)) 889 normoverride = p2.Velocity - p1.Velocity;
1263 { 890 mu = normoverride.LengthSquared();
1264 if (p2.PhysicsActorType == (int) ActorTypes.Agent) 891 if (mu > 1e-6)
1265 { 892 {
1266 if (p2 is OdeCharacter) 893 mu = 1.0f / (float)Math.Sqrt(mu);
1267 { 894 normoverride *= mu;
1268 OdeCharacter character = (OdeCharacter) p2; 895 mu = Vector3.Dot(tmp, normoverride);
1269 896 if (mu > 0)
1270 //p2.CollidingObj = true; 897 normoverride *= -1;
1271 curContact.depth = 0.00000003f; 898 }
1272 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); 899 else
1273 curContact.pos = 900 {
1274 new d.Vector3(curContact.pos.X + (p1.Size.X/2), 901 tmp.Normalize();
1275 curContact.pos.Y + (p1.Size.Y/2), 902 normoverride = -tmp;
1276 curContact.pos.Z + (p1.Size.Z/2)); 903 }
1277 character.SetPidStatus(true); 904
1278 } 905 bounce = 0;
906 mu = 0;
907 cfm = 0.0001f;
908
909 dop2foot = true;
910 if (p1.Velocity.LengthSquared() > 0.0f)
911 p1.CollidingObj = true;
912 break;
913
914 case (int)ActorTypes.Prim:
915 if ((p1.Velocity - p2.Velocity).LengthSquared() > 0.0f)
916 {
917 p1.CollidingObj = true;
918 p2.CollidingObj = true;
1279 } 919 }
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;
1280 941
1281 if (p1.PhysicsActorType == (int) ActorTypes.Agent) 942 break;
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)
1282 { 965 {
1283 if (p1 is OdeCharacter) 966 if (curContact.side1 > 0)
1284 { 967 IgnoreNegSides = true;
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 }
1296 } 968 }
1297 } 969 break;
970
971 case (int)ActorTypes.Water:
972 default:
973 ignore = true;
974 break;
1298 } 975 }
1299 } 976 break;
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;
1300 992
1301 #endregion 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;
1302 999
1303 // Logic for collision handling 1000 if (curContact.side1 > 0) // should be 2 ?
1304 // Note, that if *all* contacts are skipped (VolumeDetect) 1001 IgnoreNegSides = true;
1305 // The prim still detects (and forwards) collision events but
1306 // appears to be phantom for the world
1307 Boolean skipThisContact = false;
1308 1002
1309 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) 1003 if (Math.Abs(p2.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y) > 0.1f)
1310 skipThisContact = true; // No collision on volume detect prims 1004 mu *= frictionMovementMult;
1005 }
1006 else
1007 ignore = true;
1008 break;
1009
1010 case (int)ActorTypes.Water:
1011 default:
1012 break;
1013 }
1014 if (ignore)
1015 return;
1311 1016
1312 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) 1017 IntPtr Joint;
1313 skipThisContact = true; // No collision on volume detect prims
1314 1018
1315 if (!skipThisContact && curContact.depth < 0f) 1019 int i = 0;
1316 skipThisContact = true; 1020 while(true)
1021 {
1317 1022
1318 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) 1023 if (IgnoreNegSides && curContact.side1 < 0)
1319 skipThisContact = true; 1024 {
1025 if (++i >= count)
1026 break;
1320 1027
1321 const int maxContactsbeforedeath = 4000; 1028 if (!GetCurContactGeom(i, ref curContact))
1322 joint = IntPtr.Zero; 1029 break;
1030 }
1031 else
1323 1032
1324 if (!skipThisContact)
1325 { 1033 {
1326 _perloopContact.Add(curContact);
1327 1034
1328 if (name1 == "Terrain" || name2 == "Terrain") 1035 if (AvanormOverride)
1329 { 1036 {
1330 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && 1037 if (curContact.depth > 0.3f)
1331 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1332 { 1038 {
1333 p2ExpectedPoints = avatarExpectedContacts; 1039 if (dop1foot && (p1.Position.Z - curContact.pos.Z) > (p1.Size.Z - avCapRadius) * 0.5f)
1334 // Avatar is moving on terrain, use the movement terrain contact 1040 p1.IsColliding = true;
1335 AvatarMovementTerrainContact.geom = curContact; 1041 if (dop2foot && (p2.Position.Z - curContact.pos.Z) > (p2.Size.Z - avCapRadius) * 0.5f)
1336 1042 p2.IsColliding = true;
1337 if (m_global_contactcount < maxContactsbeforedeath) 1043 curContact.normal.X = normoverride.X;
1338 { 1044 curContact.normal.Y = normoverride.Y;
1339 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); 1045 curContact.normal.Z = normoverride.Z;
1340 m_global_contactcount++;
1341 }
1342 } 1046 }
1047
1343 else 1048 else
1344 { 1049 {
1345 if (p2.PhysicsActorType == (int)ActorTypes.Agent) 1050 if (dop1foot)
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
1358 { 1051 {
1359 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim) 1052 float sz = p1.Size.Z;
1053 Vector3 vtmp = p1.Position;
1054 float ppos = curContact.pos.Z - vtmp.Z + (sz - avCapRadius) * 0.5f;
1055 if (ppos > 0f)
1360 { 1056 {
1361 // prim prim contact 1057 if (!p1.Flying)
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)
1367 {
1368 movintYN = 1;
1369 }
1370
1371 if (p2 is OdePrim)
1372 { 1058 {
1373 material = ((OdePrim) p2).m_material; 1059 d.AABB aabb;
1374 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; 1060 d.GeomGetAABB(g2, out aabb);
1375 } 1061 float tmp = vtmp.Z - sz * .18f;
1376
1377 // Unnessesary because p1 is defined above
1378 //if (p1 is OdePrim)
1379 // {
1380 // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
1381 // }
1382 //m_log.DebugFormat("Material: {0}", material);
1383
1384 m_materialContacts[material, movintYN].geom = curContact;
1385 1062
1386 if (m_global_contactcount < maxContactsbeforedeath) 1063 if (aabb.MaxZ < tmp)
1387 { 1064 {
1388 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); 1065 vtmp.X = curContact.pos.X - vtmp.X;
1389 m_global_contactcount++; 1066 vtmp.Y = curContact.pos.Y - vtmp.Y;
1067 vtmp.Z = -0.2f;
1068 vtmp.Normalize();
1069 curContact.normal.X = vtmp.X;
1070 curContact.normal.Y = vtmp.Y;
1071 curContact.normal.Z = vtmp.Z;
1072 }
1390 } 1073 }
1391 } 1074 }
1392 else 1075 else
1393 { 1076 p1.IsColliding = true;
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 }
1400 1077
1401 int material = (int)Material.Wood;
1402
1403 if (p2 is OdePrim)
1404 {
1405 material = ((OdePrim)p2).m_material;
1406 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1407 }
1408
1409 //m_log.DebugFormat("Material: {0}", material);
1410 m_materialContacts[material, movintYN].geom = curContact;
1411
1412 if (m_global_contactcount < maxContactsbeforedeath)
1413 {
1414 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1415 m_global_contactcount++;
1416 }
1417 }
1418 } 1078 }
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 1079
1446 if (m_global_contactcount < maxContactsbeforedeath) 1080 if (dop2foot)
1447 {
1448 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1449 m_global_contactcount++;
1450 }
1451 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
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 { 1081 {
1460 // Avatar is moving on a prim, use the Movement prim contact 1082 float sz = p2.Size.Z;
1461 AvatarMovementprimContact.geom = curContact; 1083 Vector3 vtmp = p2.Position;
1462 1084 float ppos = curContact.pos.Z - vtmp.Z + (sz - avCapRadius) * 0.5f;
1463 if (m_global_contactcount < maxContactsbeforedeath) 1085 if (ppos > 0f)
1464 { 1086 {
1465 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); 1087 if (!p2.Flying)
1466 m_global_contactcount++; 1088 {
1467 } 1089 d.AABB aabb;
1468 } 1090 d.GeomGetAABB(g1, out aabb);
1469 else 1091 float tmp = vtmp.Z - sz * .18f;
1470 {
1471 // Avatar is standing still on a prim, use the non movement contact
1472 contact.geom = curContact;
1473 1092
1474 if (m_global_contactcount < maxContactsbeforedeath) 1093 if (aabb.MaxZ < tmp)
1475 { 1094 {
1476 joint = d.JointCreateContact(world, contactgroup, ref contact); 1095 vtmp.X = curContact.pos.X - vtmp.X;
1477 m_global_contactcount++; 1096 vtmp.Y = curContact.pos.Y - vtmp.Y;
1097 vtmp.Z = -0.2f;
1098 vtmp.Normalize();
1099 curContact.normal.X = vtmp.X;
1100 curContact.normal.Y = vtmp.Y;
1101 curContact.normal.Z = vtmp.Z;
1102 }
1103 }
1478 } 1104 }
1479 } 1105 else
1480 } 1106 p2.IsColliding = true;
1481 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1482 {
1483 //p1.PhysicsActorType
1484 int material = (int)Material.Wood;
1485
1486 if (p2 is OdePrim)
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;
1494 1107
1495 if (m_global_contactcount < maxContactsbeforedeath)
1496 {
1497 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1498 m_global_contactcount++;
1499 } 1108 }
1500 } 1109 }
1501 } 1110 }
1502 1111
1503 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! 1112 Joint = CreateContacJoint(ref curContact, mu, bounce, cfm, erpscale, dscale);
1504 { 1113 d.JointAttach(Joint, b1, b2);
1505 d.JointAttach(joint, b1, b2);
1506 m_global_contactcount++;
1507 }
1508 }
1509
1510 collision_accounting_events(p1, p2, maxDepthContact);
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);
1522 }
1523 }
1524 1114
1525 private bool checkDupe(d.ContactGeom contactGeom, int atype) 1115 if (++m_global_contactcount >= maxContactsbeforedeath)
1526 { 1116 break;
1527 if (!m_filterCollisions)
1528 return false;
1529
1530 bool result = false;
1531 1117
1532 ActorTypes at = (ActorTypes)atype; 1118 if (++i >= count)
1119 break;
1533 1120
1534 foreach (d.ContactGeom contact in _perloopContact) 1121 if (!GetCurContactGeom(i, ref curContact))
1535 { 1122 break;
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();
1568 1123
1569 //d.GeomGetAABB(contactGeom.g2, out aabb2); 1124 if (curContact.depth > maxDepthContact.PenetrationDepth)
1570 //d.GeomGetAABB(contactGeom.g1, out aabb1);
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 { 1125 {
1574 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) 1126 maxDepthContact.Position.X = curContact.pos.X;
1575 { 1127 maxDepthContact.Position.Y = curContact.pos.Y;
1576 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) 1128 maxDepthContact.Position.Z = curContact.pos.Z;
1577 { 1129 maxDepthContact.SurfaceNormal.X = curContact.normal.X;
1578 result = true; 1130 maxDepthContact.SurfaceNormal.Y = curContact.normal.Y;
1579 break; 1131 maxDepthContact.SurfaceNormal.Z = curContact.normal.Z;
1580 } 1132 maxDepthContact.PenetrationDepth = curContact.depth;
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 } 1133 }
1585 } 1134 }
1586 } 1135 }
1587 1136
1588 return result; 1137 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
1152 }
1153 */
1589 } 1154 }
1590 1155
1591 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) 1156 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1592 { 1157 {
1593 // obj1LocalID = 0; 1158 uint obj2LocalID = 0;
1594 //returncollisions = false;
1595 obj2LocalID = 0;
1596 //ctype = 0;
1597 //cStartStop = 0;
1598 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1599 return;
1600 1159
1601 switch ((ActorTypes)p2.PhysicsActorType) 1160 bool p1events = p1.SubscribedEvents();
1602 { 1161 bool p2events = p2.SubscribedEvents();
1603 case ActorTypes.Agent:
1604 cc2 = (OdeCharacter)p2;
1605 1162
1606 // obj1LocalID = cc2.m_localID; 1163 if (p1.IsVolumeDtc)
1607 switch ((ActorTypes)p1.PhysicsActorType) 1164 p2events = false;
1608 { 1165 if (p2.IsVolumeDtc)
1609 case ActorTypes.Agent: 1166 p1events = false;
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 1167
1623 case ActorTypes.Prim: 1168 if (!p2events && !p1events)
1624 if (p1 is OdePrim) 1169 return;
1625 {
1626 cp1 = (OdePrim) p1;
1627 obj2LocalID = cp1.LocalID;
1628 cp1.AddCollisionEvent(cc2.LocalID, contact);
1629 }
1630 //ctype = (int)CollisionCategories.Geom;
1631 1170
1632 //if (cp1.CollidingObj) 1171 Vector3 vel = Vector3.Zero;
1633 //cStartStop = (int)StatusIndicators.Generic; 1172 if (p2 != null && p2.IsPhysical)
1634 //else 1173 vel = p2.Velocity;
1635 //cStartStop = (int)StatusIndicators.Start;
1636 1174
1637 //returncollisions = true; 1175 if (p1 != null && p1.IsPhysical)
1638 break; 1176 vel -= p1.Velocity;
1639 1177
1640 case ActorTypes.Ground: 1178 contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal);
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 1179
1180 switch ((ActorTypes)p1.PhysicsActorType)
1181 {
1182 case ActorTypes.Agent:
1651 case ActorTypes.Prim: 1183 case ActorTypes.Prim:
1652
1653 if (p2 is OdePrim)
1654 { 1184 {
1655 cp2 = (OdePrim) p2; 1185 switch ((ActorTypes)p2.PhysicsActorType)
1656
1657 // obj1LocalID = cp2.m_localID;
1658 switch ((ActorTypes) p1.PhysicsActorType)
1659 { 1186 {
1660 case ActorTypes.Agent: 1187 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;
1675 case ActorTypes.Prim: 1188 case ActorTypes.Prim:
1676 1189 if (p2events)
1677 if (p1 is OdePrim)
1678 { 1190 {
1679 cp1 = (OdePrim) p1; 1191 AddCollisionEventReporting(p2);
1680 obj2LocalID = cp1.LocalID; 1192 p2.AddCollisionEvent(p1.ParentActor.LocalID, contact);
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;
1690 } 1193 }
1194 obj2LocalID = p2.ParentActor.LocalID;
1691 break; 1195 break;
1692 1196
1693 case ActorTypes.Ground: 1197 case ActorTypes.Ground:
1694 case ActorTypes.Unknown: 1198 case ActorTypes.Unknown:
1199 default:
1695 obj2LocalID = 0; 1200 obj2LocalID = 0;
1696 //ctype = (int)CollisionCategories.Land;
1697
1698 //returncollisions = true;
1699 break; 1201 break;
1700 } 1202 }
1701 1203 if (p1events)
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))
1740 { 1204 {
1741 name1 = "null"; 1205 contact.SurfaceNormal = -contact.SurfaceNormal;
1206 AddCollisionEventReporting(p1);
1207 p1.AddCollisionEvent(obj2LocalID, contact);
1742 } 1208 }
1743 if (!geom_name_map.TryGetValue(refObject, out name2)) 1209 break;
1210 }
1211 case ActorTypes.Ground:
1212 case ActorTypes.Unknown:
1213 default:
1214 {
1215 if (p2events && !p2.IsVolumeDtc)
1744 { 1216 {
1745 name2 = "null"; 1217 AddCollisionEventReporting(p2);
1218 p2.AddCollisionEvent(0, contact);
1746 } 1219 }
1747 1220 break;
1748 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2); 1221 }
1749 */ 1222 }
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;
1778 } 1223 }
1779 1224
1780 /// <summary> 1225 /// <summary>
1781 /// This is our collision testing routine in ODE 1226 /// This is our collision testing routine in ODE
1782 /// </summary> 1227 /// </summary>
1228 /// <param name="timeStep"></param>
1783 private void collision_optimized() 1229 private void collision_optimized()
1784 { 1230 {
1785 _perloopContact.Clear(); 1231 lock (_characters)
1786 1232 {
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.
1803 try 1233 try
1804 { 1234 {
1805 CollideSpaces(space, chr.Shell, IntPtr.Zero); 1235 foreach (OdeCharacter chr in _characters)
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 }
1806 } 1247 }
1807 catch (AccessViolationException) 1248 catch (AccessViolationException)
1808 { 1249 {
1809 m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", Name); 1250 m_log.Warn("[PHYSICS]: Unable to collide Character to static space");
1810 } 1251 }
1811 1252
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 //}
1818 } 1253 }
1819 1254
1820 if (CollectStats) 1255 lock (_activeprims)
1821 { 1256 {
1822 m_tempAvatarCollisionsThisFrame = _perloopContact.Count; 1257 foreach (OdePrim aprim in _activeprims)
1823 m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame; 1258 {
1259 aprim.CollisionScore = 0;
1260 aprim.IsColliding = false;
1261 }
1824 } 1262 }
1825 1263
1826 List<OdePrim> removeprims = null; 1264 // collide active prims with static enviroment
1827 foreach (OdePrim chr in _activeprims) 1265 lock (_activegroups)
1828 { 1266 {
1829 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) 1267 try
1830 { 1268 {
1831 try 1269 foreach (OdePrim prm in _activegroups)
1832 { 1270 {
1833 lock (chr) 1271 if (!prm.m_outbounds)
1834 { 1272 {
1835 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) 1273 if (d.BodyIsEnabled(prm.Body))
1836 {
1837 CollideSpaces(space, chr.prim_geom, IntPtr.Zero);
1838 }
1839 else
1840 { 1274 {
1841 if (removeprims == null) 1275 d.SpaceCollide2(StaticSpace, prm.collide_geom, IntPtr.Zero, nearCallback);
1842 { 1276 d.SpaceCollide2(GroundSpace, prm.collide_geom, IntPtr.Zero, nearCallback);
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!");
1848 } 1277 }
1849 } 1278 }
1850 } 1279 }
1851 catch (AccessViolationException)
1852 {
1853 m_log.Error("[ODE SCENE]: Unable to space collide");
1854 }
1855 } 1280 }
1856 } 1281 catch (AccessViolationException)
1857
1858 if (CollectStats)
1859 m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame;
1860
1861 if (removeprims != null)
1862 {
1863 foreach (OdePrim chr in removeprims)
1864 { 1282 {
1865 _activeprims.Remove(chr); 1283 m_log.Warn("[PHYSICS]: Unable to collide Active prim to static space");
1866 } 1284 }
1867 } 1285 }
1868 } 1286 // finally colide active things amoung them
1869 1287 try
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))
1888 { 1288 {
1889 if (heightFieldGeom != IntPtr.Zero) 1289 d.SpaceCollide(ActiveSpace, IntPtr.Zero, nearCallback);
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
1926 } 1290 }
1927 else 1291 catch (AccessViolationException)
1928 { 1292 {
1929 return 0f; 1293 m_log.Warn("[PHYSICS]: Unable to collide in Active space");
1930 } 1294 }
1931 } 1295// _perloopContact.Clear();
1932// End recovered. Kitto Flora 1296 }
1933 1297
1298 #endregion
1934 /// <summary> 1299 /// <summary>
1935 /// Add actor to the list that should receive collision events in the simulate loop. 1300 /// Add actor to the list that should receive collision events in the simulate loop.
1936 /// </summary> 1301 /// </summary>
1937 /// <param name="obj"></param> 1302 /// <param name="obj"></param>
1938 internal void AddCollisionEventReporting(PhysicsActor obj) 1303 public void AddCollisionEventReporting(PhysicsActor obj)
1939 { 1304 {
1940// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID); 1305 if (!_collisionEventPrim.Contains(obj))
1941 1306 _collisionEventPrim.Add(obj);
1942 lock (m_collisionEventActorsChanges)
1943 m_collisionEventActorsChanges[obj.LocalID] = obj;
1944 } 1307 }
1945 1308
1946 /// <summary> 1309 /// <summary>
1947 /// Remove actor from the list that should receive collision events in the simulate loop. 1310 /// Remove actor from the list that should receive collision events in the simulate loop.
1948 /// </summary> 1311 /// </summary>
1949 /// <param name="obj"></param> 1312 /// <param name="obj"></param>
1950 internal void RemoveCollisionEventReporting(PhysicsActor obj) 1313 public void RemoveCollisionEventReporting(PhysicsActor obj)
1951 { 1314 {
1952// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID); 1315 if (_collisionEventPrim.Contains(obj) && !_collisionEventPrimRemove.Contains(obj))
1316 _collisionEventPrimRemove.Add(obj);
1317 }
1953 1318
1954 lock (m_collisionEventActorsChanges) 1319 public override float TimeDilation
1955 m_collisionEventActorsChanges[obj.LocalID] = null; 1320 {
1321 get { return m_timeDilation; }
1322 }
1323
1324 public override bool SupportsNINJAJoints
1325 {
1326 get { return false; }
1956 } 1327 }
1957 1328
1958 #region Add/Remove Entities 1329 #region Add/Remove Entities
@@ -1963,470 +1334,118 @@ namespace OpenSim.Region.Physics.OdePlugin
1963 pos.X = position.X; 1334 pos.X = position.X;
1964 pos.Y = position.Y; 1335 pos.Y = position.Y;
1965 pos.Z = position.Z; 1336 pos.Z = position.Z;
1966 1337 OdeCharacter newAv = new OdeCharacter(avName, this, pos, size, avPIDD, avPIDP, avCapRadius, avDensity, avMovementDivisorWalk, avMovementDivisorRun);
1967 OdeCharacter newAv
1968 = new OdeCharacter(
1969 avName, this, pos, size, avPIDD, avPIDP,
1970 avCapRadius, avStandupTensor, avDensity,
1971 avMovementDivisorWalk, avMovementDivisorRun);
1972
1973 newAv.Flying = isFlying; 1338 newAv.Flying = isFlying;
1974 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; 1339 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1975 1340
1976 return newAv; 1341 return newAv;
1977 } 1342 }
1978 1343
1979 public override void RemoveAvatar(PhysicsActor actor) 1344 public void AddCharacter(OdeCharacter chr)
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)
1989 { 1345 {
1990 if (!_characters.Contains(chr)) 1346 lock (_characters)
1991 {
1992 _characters.Add(chr);
1993
1994// m_log.DebugFormat(
1995// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}",
1996// chr.Name, chr.LocalID, Name, _characters.Count);
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 { 1347 {
2003 m_log.ErrorFormat( 1348 if (!_characters.Contains(chr))
2004 "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!", 1349 {
2005 chr.Name, chr.LocalID); 1350 _characters.Add(chr);
1351 if (chr.bad)
1352 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1353 }
2006 } 1354 }
2007 } 1355 }
2008 1356
2009 internal void RemoveCharacter(OdeCharacter chr) 1357 public void RemoveCharacter(OdeCharacter chr)
2010 { 1358 {
2011 if (_characters.Contains(chr)) 1359 lock (_characters)
2012 {
2013 _characters.Remove(chr);
2014
2015// m_log.DebugFormat(
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 { 1360 {
2021 m_log.ErrorFormat( 1361 if (_characters.Contains(chr))
2022 "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!", 1362 {
2023 chr.Name, chr.LocalID); 1363 _characters.Remove(chr);
1364 }
2024 } 1365 }
2025 } 1366 }
2026 1367
2027 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, 1368 public void BadCharacter(OdeCharacter chr)
2028 PrimitiveBaseShape pbs, bool isphysical, uint localID)
2029 { 1369 {
2030 Vector3 pos = position; 1370 lock (_badCharacter)
2031 Vector3 siz = size;
2032 Quaternion rot = rotation;
2033
2034 OdePrim newPrim;
2035 lock (OdeLock)
2036 { 1371 {
2037 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical); 1372 if (!_badCharacter.Contains(chr))
2038 1373 _badCharacter.Add(chr);
2039 lock (_prims)
2040 _prims.Add(newPrim);
2041 } 1374 }
2042 newPrim.LocalID = localID;
2043 return newPrim;
2044 }
2045
2046 /// <summary>
2047 /// Make this prim subject to physics.
2048 /// </summary>
2049 /// <param name="prim"></param>
2050 internal void ActivatePrim(OdePrim prim)
2051 {
2052 // adds active prim.. (ones that should be iterated over in collisions_optimized
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 } 1375 }
2058 1376
2059 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, 1377 public override void RemoveAvatar(PhysicsActor actor)
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);
2065 }
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 }
2083
2084 // internal utility function: must be called within a lock (OdeLock)
2085 private void InternalAddPendingJoint(OdePhysicsJoint joint)
2086 {
2087 pendingJoints.Add(joint);
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 { 1378 {
2094 pendingJoints.Remove(joint); 1379 //m_log.Debug("[PHYSICS]:ODELOCK");
2095 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene); 1380 ((OdeCharacter) actor).Destroy();
2096 } 1381 }
2097 1382
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 1383
2105 public override void DumpJointInfo() 1384 public void addActivePrim(OdePrim activatePrim)
2106 { 1385 {
2107 string hdr = "[NINJA] JOINTINFO: "; 1386 // adds active prim..
2108 foreach (PhysicsJoint j in pendingJoints) 1387 lock (_activeprims)
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)
2132 { 1388 {
2133 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it"); 1389 if (!_activeprims.Contains(activatePrim))
2134 foreach (PhysicsJoint j in joints_connecting_actor[actorName]) 1390 _activeprims.Add(activatePrim);
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");
2139 } 1391 }
2140 } 1392 }
2141 1393
2142 public override void RequestJointDeletion(string ObjectNameInScene) 1394 public void addActiveGroups(OdePrim activatePrim)
2143 { 1395 {
2144 lock (externalJointRequestsLock) 1396 lock (_activegroups)
2145 { 1397 {
2146 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously 1398 if (!_activegroups.Contains(activatePrim))
2147 { 1399 _activegroups.Add(activatePrim);
2148 requestedJointsToBeDeleted.Add(ObjectNameInScene);
2149 }
2150 } 1400 }
2151 } 1401 }
2152 1402
2153 private void DeleteRequestedJoints() 1403 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1404 PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, byte shapeType, uint localID)
2154 { 1405 {
2155 List<string> myRequestedJointsToBeDeleted; 1406 OdePrim newPrim;
2156 lock (externalJointRequestsLock) 1407 lock (OdeLock)
2157 {
2158 // make a local copy of the shared list for processing (threading issues)
2159 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
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 { 1408 {
2224 foreach (string jointName in myRequestedJointsToBeDeleted) 1409 newPrim = new OdePrim(name, this, position, size, rotation, pbs, isphysical, isPhantom, shapeType, localID);
2225 { 1410 lock (_prims)
2226 requestedJointsToBeDeleted.Remove(jointName); 1411 _prims.Add(newPrim);
2227 }
2228 } 1412 }
1413 return newPrim;
2229 } 1414 }
2230 1415
2231 // for pending joints we don't know if their associated bodies exist yet or not. 1416 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
2232 // the joint is actually created during processing of the taints 1417 Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, uint localid)
2233 private void CreateRequestedJoints()
2234 { 1418 {
2235 List<PhysicsJoint> myRequestedJointsToBeCreated; 1419 return AddPrim(primName, position, size, rotation, pbs, isPhysical, isPhantom, 0 , localid);
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 }
2256
2257 InternalAddPendingJoint(joint as OdePhysicsJoint);
2258
2259 if (joint.BodyNames.Count >= 2)
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 } 1420 }
2286 1421
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)
2306 {
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;
2328 }
2329 1422
2330 private void RemoveAllJointsConnectedToActor(PhysicsActor actor) 1423 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1424 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
2331 { 1425 {
2332 //m_log.Debug("RemoveAllJointsConnectedToActor: start"); 1426 return AddPrim(primName, position, size, rotation, pbs, isPhysical,false, 0, localid);
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 } 1427 }
2350 1428
2351 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) 1429 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1430 Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid)
2352 { 1431 {
2353 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start"); 1432
2354 lock (OdeLock) 1433 return AddPrim(primName, position, size, rotation, pbs, isPhysical,isPhantom, shapeType, localid);
2355 {
2356 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2357 RemoveAllJointsConnectedToActor(actor);
2358 }
2359 } 1434 }
2360 1435
2361 // normally called from within OnJointMoved, which is called from within a lock (OdeLock) 1436 public void remActivePrim(OdePrim deactivatePrim)
2362 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2363 { 1437 {
2364 Debug.Assert(joint.IsInPhysicsEngine); 1438 lock (_activeprims)
2365 d.Vector3 pos = new d.Vector3();
2366
2367 if (!(joint is OdePhysicsJoint))
2368 { 1439 {
2369 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); 1440 _activeprims.Remove(deactivatePrim);
2370 } 1441 }
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);
2385 } 1442 }
2386 1443 public void remActiveGroup(OdePrim deactivatePrim)
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)
2399 { 1444 {
2400 Debug.Assert(joint.IsInPhysicsEngine); 1445 lock (_activegroups)
2401 d.Vector3 axis = new d.Vector3();
2402
2403 if (!(joint is OdePhysicsJoint))
2404 { 1446 {
2405 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); 1447 _activegroups.Remove(deactivatePrim);
2406 } 1448 }
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);
2430 } 1449 }
2431 1450
2432 public override void RemovePrim(PhysicsActor prim) 1451 public override void RemovePrim(PhysicsActor prim)
@@ -2435,16 +1454,14 @@ namespace OpenSim.Region.Physics.OdePlugin
2435 // removed in the next physics simulate pass. 1454 // removed in the next physics simulate pass.
2436 if (prim is OdePrim) 1455 if (prim is OdePrim)
2437 { 1456 {
2438 lock (OdeLock) 1457// lock (OdeLock)
2439 { 1458 {
2440 OdePrim p = (OdePrim) prim; 1459
2441 1460 OdePrim p = (OdePrim)prim;
2442 p.setPrimForRemoval(); 1461 p.setPrimForRemoval();
2443 AddPhysicsActorTaint(prim);
2444 } 1462 }
2445 } 1463 }
2446 } 1464 }
2447
2448 /// <summary> 1465 /// <summary>
2449 /// This is called from within simulate but outside the locked portion 1466 /// This is called from within simulate but outside the locked portion
2450 /// We need to do our own locking here 1467 /// We need to do our own locking here
@@ -2457,772 +1474,473 @@ namespace OpenSim.Region.Physics.OdePlugin
2457 /// that the space was using. 1474 /// that the space was using.
2458 /// </summary> 1475 /// </summary>
2459 /// <param name="prim"></param> 1476 /// <param name="prim"></param>
2460 internal void RemovePrimThreadLocked(OdePrim prim) 1477 public void RemovePrimThreadLocked(OdePrim prim)
2461 { 1478 {
2462// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID); 1479 //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2463
2464 lock (prim) 1480 lock (prim)
2465 { 1481 {
2466 RemoveCollisionEventReporting(prim); 1482// RemoveCollisionEventReporting(prim);
2467 1483 lock (_prims)
2468 if (prim.prim_geom != IntPtr.Zero) 1484 _prims.Remove(prim);
2469 {
2470 prim.ResetTaints();
2471
2472 if (prim.IsPhysical)
2473 {
2474 prim.disableBody();
2475 if (prim.childPrim)
2476 {
2477 prim.childPrim = false;
2478 prim.Body = IntPtr.Zero;
2479 prim.m_disabled = true;
2480 prim.IsPhysical = false;
2481 }
2482
2483
2484 }
2485 // we don't want to remove the main space
2486
2487 // If the geometry is in the targetspace, remove it from the target space
2488 //m_log.Warn(prim.m_targetSpace);
2489
2490 //if (prim.m_targetSpace != IntPtr.Zero)
2491 //{
2492 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
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 }
2542 } 1485 }
2543 }
2544 1486
2545 #endregion 1487 }
2546 1488
2547 #region Space Separation Calculation 1489 public bool havePrim(OdePrim prm)
1490 {
1491 lock (_prims)
1492 return _prims.Contains(prm);
1493 }
2548 1494
2549 /// <summary> 1495 public bool haveActor(PhysicsActor actor)
2550 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2551 /// </summary>
2552 /// <param name="pSpace"></param>
2553 private void resetSpaceArrayItemToZero(IntPtr pSpace)
2554 { 1496 {
2555 for (int x = 0; x < staticPrimspace.GetLength(0); x++) 1497 if (actor is OdePrim)
2556 { 1498 {
2557 for (int y = 0; y < staticPrimspace.GetLength(1); y++) 1499 lock (_prims)
2558 { 1500 return _prims.Contains((OdePrim)actor);
2559 if (staticPrimspace[x, y] == pSpace) 1501 }
2560 staticPrimspace[x, y] = IntPtr.Zero; 1502 else if (actor is OdeCharacter)
2561 } 1503 {
1504 lock (_characters)
1505 return _characters.Contains((OdeCharacter)actor);
2562 } 1506 }
1507 return false;
2563 } 1508 }
2564 1509
2565// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY) 1510 #endregion
2566// { 1511
2567// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; 1512 #region Space Separation Calculation
2568// }
2569 1513
2570 /// <summary> 1514 /// <summary>
2571 /// Called when a static prim moves. Allocates a space for the prim based on its position 1515 /// Called when a static prim moves or becomes static
1516 /// Places the prim in a space one the static sub-spaces grid
2572 /// </summary> 1517 /// </summary>
2573 /// <param name="geom">the pointer to the geom that moved</param> 1518 /// <param name="geom">the pointer to the geom that moved</param>
2574 /// <param name="pos">the position that the geom moved to</param> 1519 /// <param name="pos">the position that the geom moved to</param>
2575 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param> 1520 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2576 /// <returns>a pointer to the new space it's in</returns> 1521 /// <returns>a pointer to the new space it's in</returns>
2577 internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace) 1522 public IntPtr MoveGeomToStaticSpace(IntPtr geom, Vector3 pos, IntPtr currentspace)
2578 { 1523 {
2579 // Called from setting the Position and Size of an ODEPrim so 1524 // moves a prim into another static sub-space or from another space into a static sub-space
1525
1526 // Called ODEPrim so
2580 // it's already in locked space. 1527 // it's already in locked space.
2581 1528
2582 // we don't want to remove the main space 1529 if (geom == IntPtr.Zero) // shouldn't happen
2583 // we don't need to test physical here because this function should 1530 return IntPtr.Zero;
2584 // never be called if the prim is physical(active)
2585 1531
2586 // All physical prim end up in the root space 1532 // get the static sub-space for current position
2587 //Thread.Sleep(20); 1533 IntPtr newspace = calculateSpaceForGeom(pos);
2588 if (currentspace != space) 1534
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))
2589 { 1540 {
2590 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString()); 1541 if (d.GeomIsSpace(currentspace))
2591 //if (currentspace == IntPtr.Zero)
2592 //{
2593 //int adfadf = 0;
2594 //}
2595 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2596 { 1542 {
2597 if (d.GeomIsSpace(currentspace)) 1543 waitForSpaceUnlock(currentspace);
2598 { 1544 d.SpaceRemove(currentspace, geom);
2599// waitForSpaceUnlock(currentspace); 1545
2600 d.SpaceRemove(currentspace, geom); 1546 if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0)
2601 }
2602 else
2603 { 1547 {
2604 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + 1548 d.SpaceDestroy(currentspace);
2605 " Geom:" + geom);
2606 } 1549 }
2607 } 1550 }
2608 else 1551 else
2609 { 1552 {
2610 IntPtr sGeomIsIn = d.GeomGetSpace(geom); 1553 m_log.Info("[Physics]: Invalid or empty Space passed to 'MoveGeomToStaticSpace':" + currentspace +
2611 if (sGeomIsIn != IntPtr.Zero) 1554 " Geom:" + geom);
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 }
2647 } 1555 }
2648 } 1556 }
2649 else 1557 else // odd currentspace is null or doesn't contain the geom? lets try the geom ideia of current space
2650 { 1558 {
2651 // this is a physical object that got disabled. ;.; 1559 currentspace = d.GeomGetSpace(geom);
2652 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero) 1560 if (currentspace != IntPtr.Zero)
2653 { 1561 {
2654 if (d.SpaceQuery(currentspace, geom)) 1562 if (d.GeomIsSpace(currentspace))
2655 {
2656 if (d.GeomIsSpace(currentspace))
2657 {
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 { 1563 {
2669 IntPtr sGeomIsIn = d.GeomGetSpace(geom); 1564 waitForSpaceUnlock(currentspace);
2670 if (sGeomIsIn != IntPtr.Zero) 1565 d.SpaceRemove(currentspace, geom);
1566
1567 if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0)
2671 { 1568 {
2672 if (d.GeomIsSpace(sGeomIsIn)) 1569 d.SpaceDestroy(currentspace);
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 }
2682 } 1570 }
1571
2683 } 1572 }
2684 } 1573 }
2685 } 1574 }
2686 1575
2687 // The routines in the Position and Size sections do the 'inserting' into the space, 1576 // put the geom in the newspace
2688 // so all we have to do is make sure that the space that we're putting the prim into 1577 waitForSpaceUnlock(newspace);
2689 // is in the 'main' space. 1578 d.SpaceAdd(newspace, geom);
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 }
2698 1579
1580 // let caller know this newspace
2699 return newspace; 1581 return newspace;
2700 } 1582 }
2701 1583
2702 /// <summary> 1584 /// <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>
2721 /// Calculates the space the prim should be in by its position 1585 /// Calculates the space the prim should be in by its position
2722 /// </summary> 1586 /// </summary>
2723 /// <param name="pos"></param> 1587 /// <param name="pos"></param>
2724 /// <returns>a pointer to the space. This could be a new space or reused space.</returns> 1588 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2725 internal IntPtr calculateSpaceForGeom(Vector3 pos) 1589 public 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)
2738 { 1590 {
2739 int[] returnint = new int[2]; 1591 int x, y;
2740 1592
2741 returnint[0] = (int) (pos.X/metersInSpace); 1593 if (pos.X < 0)
1594 return staticPrimspaceOffRegion[0];
2742 1595
2743 if (returnint[0] > ((int) (259f/metersInSpace))) 1596 if (pos.Y < 0)
2744 returnint[0] = ((int) (259f/metersInSpace)); 1597 return staticPrimspaceOffRegion[2];
2745 if (returnint[0] < 0)
2746 returnint[0] = 0;
2747 1598
2748 returnint[1] = (int) (pos.Y/metersInSpace); 1599 x = (int)(pos.X * spacesPerMeter);
2749 if (returnint[1] > ((int) (259f/metersInSpace))) 1600 if (x > spaceGridMaxX)
2750 returnint[1] = ((int) (259f/metersInSpace)); 1601 return staticPrimspaceOffRegion[1];
2751 if (returnint[1] < 0) 1602
2752 returnint[1] = 0; 1603 y = (int)(pos.Y * spacesPerMeter);
1604 if (y > spaceGridMaxY)
1605 return staticPrimspaceOffRegion[3];
2753 1606
2754 return returnint; 1607 return staticPrimspace[x, y];
2755 } 1608 }
2756 1609
2757 #endregion 1610 #endregion
2758 1611
1612
2759 /// <summary> 1613 /// <summary>
2760 /// Routine to figure out if we need to mesh this prim with our mesher 1614 /// Called to queue a change to a actor
1615 /// to use in place of old taint mechanism so changes do have a time sequence
2761 /// </summary> 1616 /// </summary>
2762 /// <param name="pbs"></param>
2763 /// <returns></returns>
2764 internal bool needsMeshing(PrimitiveBaseShape pbs)
2765 {
2766 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2767 // but we still need to check for sculptie meshing being enabled so this is the most
2768 // convenient place to do it for now...
2769
2770 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2771 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2772 int iPropertiesNotSupportedDefault = 0;
2773
2774 if (pbs.SculptEntry && !meshSculptedPrim)
2775 {
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))
2788 {
2789
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 }
2803 }
2804 }
2805
2806 if (pbs.ProfileHollow != 0)
2807 iPropertiesNotSupportedDefault++;
2808 1617
2809 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) 1618 public void AddChange(PhysicsActor actor, changes what, Object arg)
2810 iPropertiesNotSupportedDefault++; 1619 {
2811 1620 ODEchangeitem item = new ODEchangeitem();
2812 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) 1621 item.actor = actor;
2813 iPropertiesNotSupportedDefault++; 1622 item.what = what;
2814 1623 item.arg = arg;
2815 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) 1624 ChangesQueue.Enqueue(item);
2816 iPropertiesNotSupportedDefault++;
2817
2818 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2819 iPropertiesNotSupportedDefault++;
2820
2821 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2822 iPropertiesNotSupportedDefault++;
2823
2824 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2825 iPropertiesNotSupportedDefault++;
2826
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))
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)
2837 {
2838 iPropertiesNotSupportedDefault++;
2839 }
2840 }
2841 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2842 {
2843 if (pbs.PathCurve == (byte)Extrusion.Straight)
2844 {
2845 iPropertiesNotSupportedDefault++;
2846 }
2847
2848 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2849 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2850 {
2851 iPropertiesNotSupportedDefault++;
2852 }
2853 }
2854 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2855 {
2856 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2857 {
2858 iPropertiesNotSupportedDefault++;
2859 }
2860 }
2861 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2862 {
2863 if (pbs.PathCurve == (byte)Extrusion.Straight)
2864 {
2865 iPropertiesNotSupportedDefault++;
2866 }
2867 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
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 } 1625 }
2888 1626
2889 /// <summary> 1627 /// <summary>
2890 /// Called after our prim properties are set Scale, position etc. 1628 /// 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 1629 /// 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 1630 /// This assures us that we have no race conditions
2895 /// </remarks> 1631 /// </summary>
2896 /// <param name="actor"></param> 1632 /// <param name="prim"></param>
2897 public override void AddPhysicsActorTaint(PhysicsActor actor) 1633 public override void AddPhysicsActorTaint(PhysicsActor prim)
2898 { 1634 {
2899 if (actor is OdePrim) 1635 }
2900 { 1636
2901 OdePrim taintedprim = ((OdePrim)actor); 1637 // does all pending changes generated during region load process
2902 lock (_taintedPrims) 1638 public override void PrepareSimulation()
2903 _taintedPrims.Add(taintedprim); 1639 {
2904 } 1640 lock (OdeLock)
2905 else if (actor is OdeCharacter)
2906 { 1641 {
2907 OdeCharacter taintedchar = ((OdeCharacter)actor); 1642 if (world == IntPtr.Zero)
2908 lock (_taintedActors)
2909 { 1643 {
2910 _taintedActors.Add(taintedchar); 1644 ChangesQueue.Clear();
2911 if (taintedchar.bad) 1645 return;
2912 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); 1646 }
1647
1648 ODEchangeitem item;
1649
1650 int donechanges = 0;
1651 if (ChangesQueue.Count > 0)
1652 {
1653 m_log.InfoFormat("[ODE] start processing pending actor operations");
1654 int tstart = Util.EnvironmentTickCount();
1655
1656 while (ChangesQueue.Dequeue(out item))
1657 {
1658 if (item.actor != null)
1659 {
1660 try
1661 {
1662 if (item.actor is OdeCharacter)
1663 ((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
1664 else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
1665 RemovePrimThreadLocked((OdePrim)item.actor);
1666 }
1667 catch
1668 {
1669 m_log.WarnFormat("[PHYSICS]: Operation failed for a actor {0} {1}",
1670 item.actor.Name, item.what.ToString());
1671 }
1672 }
1673 donechanges++;
1674 }
1675 int time = Util.EnvironmentTickCountSubtract(tstart);
1676 m_log.InfoFormat("[ODE] finished {0} operations in {1}ms", donechanges, time);
2913 } 1677 }
2914 } 1678 }
2915 } 1679 }
2916 1680
2917 /// <summary> 1681 /// <summary>
2918 /// This is our main simulate loop 1682 /// This is our main simulate loop
2919 /// </summary>
2920 /// <remarks>
2921 /// It's thread locked by a Mutex in the scene. 1683 /// It's thread locked by a Mutex in the scene.
2922 /// It holds Collisions, it instructs ODE to step through the physical reactions 1684 /// It holds Collisions, it instructs ODE to step through the physical reactions
2923 /// It moves the objects around in memory 1685 /// It moves the objects around in memory
2924 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) 1686 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2925 /// </remarks> 1687 /// </summary>
2926 /// <param name="timeStep"></param> 1688 /// <param name="timeStep"></param>
2927 /// <returns>The number of frames simulated over that period.</returns> 1689 /// <returns></returns>
2928 public override float Simulate(float timeStep) 1690 public override float Simulate(float timeStep)
2929 { 1691 {
2930 if (!_worldInitialized) return 11f;
2931 1692
2932 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; 1693 DateTime now = DateTime.UtcNow;
2933 int tempTick = 0, tempTick2 = 0; 1694 TimeSpan timedif = now - m_lastframe;
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;
2934 1703
2935 if (framecount >= int.MaxValue) 1704 if (framecount < 0)
2936 framecount = 0; 1705 framecount = 0;
2937 1706
2938 framecount++; 1707 framecount++;
2939 1708
2940 float fps = 0; 1709 int curphysiteractions;
2941 1710
2942 float timeLeft = timeStep; 1711 // if in trouble reduce step resolution
2943 1712 if (step_time >= m_SkipFramesAtms)
2944 //m_log.Info(timeStep.ToString()); 1713 curphysiteractions = m_physicsiterations / 2;
2945// step_time += timeSte 1714 else
2946// 1715 curphysiteractions = m_physicsiterations;
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)
2967 {
2968 foreach (KeyValuePair<uint, PhysicsActor> kvp in m_collisionEventActorsChanges)
2969 {
2970 if (kvp.Value == null)
2971 m_collisionEventActors.Remove(kvp.Key);
2972 else
2973 m_collisionEventActors[kvp.Key] = kvp.Value;
2974 }
2975 1716
2976 m_collisionEventActorsChanges.Clear(); 1717 int nodeframes = 0;
2977 }
2978 1718
2979 if (SupportsNINJAJoints) 1719// checkThread();
2980 {
2981 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2982 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2983 }
2984 1720
2985 lock (OdeLock) 1721 lock (SimulationLock)
1722 lock(OdeLock)
2986 { 1723 {
2987 // Process 10 frames if the sim is running normal.. 1724 if (world == IntPtr.Zero)
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)
3008 { 1725 {
3009 try 1726 ChangesQueue.Clear();
3010 { 1727 return 0;
3011 if (CollectStats) 1728 }
3012 tempTick = Util.EnvironmentTickCount();
3013
3014 lock (_taintedActors)
3015 {
3016 foreach (OdeCharacter character in _taintedActors)
3017 character.ProcessTaints();
3018 1729
3019 _taintedActors.Clear(); 1730 ODEchangeitem item;
3020 }
3021 1731
3022 if (CollectStats) 1732 if (ChangesQueue.Count > 0)
3023 { 1733 {
3024 tempTick2 = Util.EnvironmentTickCount(); 1734 int ttmpstart = Util.EnvironmentTickCount();
3025 m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); 1735 int ttmp;
3026 tempTick = tempTick2;
3027 }
3028 1736
3029 lock (_taintedPrims) 1737 while (ChangesQueue.Dequeue(out item))
1738 {
1739 if (item.actor != null)
3030 { 1740 {
3031 foreach (OdePrim prim in _taintedPrims) 1741 try
3032 { 1742 {
3033 if (prim.m_taintremove) 1743 if (item.actor is OdeCharacter)
3034 { 1744 ((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
3035// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name); 1745 else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
3036 RemovePrimThreadLocked(prim); 1746 RemovePrimThreadLocked((OdePrim)item.actor);
3037 } 1747 }
3038 else 1748 catch
3039 { 1749 {
3040// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name); 1750 m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}",
3041 prim.ProcessTaints(); 1751 item.actor.Name, item.what.ToString());
3042 }
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();
3051 } 1752 }
3052
3053 if (SupportsNINJAJoints)
3054 SimulatePendingNINJAJoints();
3055
3056 _taintedPrims.Clear();
3057 } 1753 }
1754 ttmp = Util.EnvironmentTickCountSubtract(ttmpstart);
1755 if (ttmp > 20)
1756 break;
1757 }
1758 }
1759
1760 d.WorldSetQuickStepNumIterations(world, curphysiteractions);
3058 1761
3059 if (CollectStats) 1762 while (step_time > HalfOdeStep && nodeframes < 10) //limit number of steps so we don't say here for ever
3060 { 1763 {
3061 tempTick2 = Util.EnvironmentTickCount(); 1764 try
3062 m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); 1765 {
3063 tempTick = tempTick2; 1766 // clear pointer/counter to contacts to pass into joints
3064 } 1767 m_global_contactcount = 0;
3065 1768
3066 // Move characters
3067 foreach (OdeCharacter actor in _characters)
3068 actor.Move(defects);
3069 1769
3070 if (defects.Count != 0) 1770 // Move characters
1771 lock (_characters)
3071 { 1772 {
3072 foreach (OdeCharacter actor in defects) 1773 List<OdeCharacter> defects = new List<OdeCharacter>();
1774 foreach (OdeCharacter actor in _characters)
3073 { 1775 {
3074 m_log.ErrorFormat( 1776 if (actor != null)
3075 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving", 1777 actor.Move(ODE_STEPSIZE, defects);
3076 actor.Name, actor.LocalID, Name); 1778 }
3077 1779 if (defects.Count != 0)
3078 RemoveCharacter(actor); 1780 {
3079 actor.DestroyOdeStructures(); 1781 foreach (OdeCharacter defect in defects)
1782 {
1783 RemoveCharacter(defect);
1784 }
1785 defects.Clear();
3080 } 1786 }
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 } 1787 }
3091 1788
3092 // Move other active objects 1789 // Move other active objects
3093 foreach (OdePrim prim in _activeprims) 1790 lock (_activegroups)
3094 {
3095 prim.m_collisionscore = 0;
3096 prim.Move(timeStep);
3097 }
3098
3099 if (CollectStats)
3100 { 1791 {
3101 tempTick2 = Util.EnvironmentTickCount(); 1792 foreach (OdePrim aprim in _activegroups)
3102 m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); 1793 {
3103 tempTick = tempTick2; 1794 aprim.Move();
1795 }
3104 } 1796 }
3105 1797
3106 //if ((framecount % m_randomizeWater) == 0) 1798 //if ((framecount % m_randomizeWater) == 0)
3107 // randomizeWater(waterlevel); 1799 // randomizeWater(waterlevel);
3108 1800
3109 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
3110 m_rayCastManager.ProcessQueuedRequests(); 1801 m_rayCastManager.ProcessQueuedRequests();
3111 1802
3112 if (CollectStats)
3113 {
3114 tempTick2 = Util.EnvironmentTickCount();
3115 m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3116 tempTick = tempTick2;
3117 }
3118
3119 collision_optimized(); 1803 collision_optimized();
3120 1804
3121 if (CollectStats) 1805 foreach (PhysicsActor obj in _collisionEventPrim)
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)
3129 { 1806 {
3130// m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID); 1807 if (obj == null)
1808 continue;
3131 1809
3132 switch ((ActorTypes)obj.PhysicsActorType) 1810 switch ((ActorTypes)obj.PhysicsActorType)
3133 { 1811 {
3134 case ActorTypes.Agent: 1812 case ActorTypes.Agent:
3135 OdeCharacter cobj = (OdeCharacter)obj; 1813 OdeCharacter cobj = (OdeCharacter)obj;
3136 cobj.AddCollisionFrameTime(100); 1814 cobj.AddCollisionFrameTime((int)(odetimestepMS));
3137 cobj.SendCollisions(); 1815 cobj.SendCollisions();
3138 break; 1816 break;
3139 1817
3140 case ActorTypes.Prim: 1818 case ActorTypes.Prim:
3141 OdePrim pobj = (OdePrim)obj; 1819 OdePrim pobj = (OdePrim)obj;
3142 pobj.SendCollisions(); 1820 if (pobj.Body == IntPtr.Zero || (d.BodyIsEnabled(pobj.Body) && !pobj.m_outbounds))
1821 if (!pobj.m_outbounds)
1822 {
1823 pobj.AddCollisionFrameTime((int)(odetimestepMS));
1824 pobj.SendCollisions();
1825 }
3143 break; 1826 break;
3144 } 1827 }
3145 } 1828 }
3146 1829
3147// if (m_global_contactcount > 0) 1830 foreach (PhysicsActor obj in _collisionEventPrimRemove)
3148// m_log.DebugFormat( 1831 _collisionEventPrim.Remove(obj);
3149// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount);
3150
3151 m_global_contactcount = 0;
3152 1832
3153 if (CollectStats) 1833 _collisionEventPrimRemove.Clear();
3154 {
3155 tempTick2 = Util.EnvironmentTickCount();
3156 m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3157 tempTick = tempTick2;
3158 }
3159 1834
1835 // do a ode simulation step
3160 d.WorldQuickStep(world, ODE_STEPSIZE); 1836 d.WorldQuickStep(world, ODE_STEPSIZE);
1837 d.JointGroupEmpty(contactgroup);
3161 1838
3162 if (CollectStats) 1839 // update managed ideia of physical data and do updates to core
3163 m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); 1840 /*
1841 lock (_characters)
1842 {
1843 foreach (OdeCharacter actor in _characters)
1844 {
1845 if (actor != null)
1846 {
1847 if (actor.bad)
1848 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3164 1849
3165 d.JointGroupEmpty(contactgroup); 1850 actor.UpdatePositionAndVelocity();
1851 }
1852 }
1853 }
1854 */
1855
1856 lock (_activegroups)
1857 {
1858 {
1859 foreach (OdePrim actor in _activegroups)
1860 {
1861 if (actor.IsPhysical)
1862 {
1863 actor.UpdatePositionAndVelocity();
1864 }
1865 }
1866 }
1867 }
3166 } 1868 }
3167 catch (Exception e) 1869 catch (Exception e)
3168 { 1870 {
3169 m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e); 1871 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
1872// ode.dunlock(world);
3170 } 1873 }
3171 1874
3172 timeLeft -= ODE_STEPSIZE;
3173 }
3174 1875
3175 if (CollectStats) 1876 step_time -= ODE_STEPSIZE;
3176 tempTick = Util.EnvironmentTickCount(); 1877 nodeframes++;
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);
3184 } 1878 }
3185 1879
3186 if (defects.Count != 0) 1880 lock (_badCharacter)
3187 { 1881 {
3188 foreach (OdeCharacter actor in defects) 1882 if (_badCharacter.Count > 0)
3189 { 1883 {
3190 m_log.ErrorFormat( 1884 foreach (OdeCharacter chr in _badCharacter)
3191 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity", 1885 {
3192 actor.Name, actor.LocalID, Name); 1886 RemoveCharacter(chr);
1887 }
3193 1888
3194 RemoveCharacter(actor); 1889 _badCharacter.Clear();
3195 actor.DestroyOdeStructures();
3196 } 1890 }
3197
3198 defects.Clear();
3199 } 1891 }
3200 1892
3201 if (CollectStats) 1893 timedif = now - m_lastMeshExpire;
1894
1895 if (timedif.Seconds > 10)
3202 { 1896 {
3203 tempTick2 = Util.EnvironmentTickCount(); 1897 mesher.ExpireReleaseMeshs();
3204 m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); 1898 m_lastMeshExpire = now;
3205 tempTick = tempTick2;
3206 } 1899 }
3207 1900
3208 //if (timeStep < 0.2f) 1901// information block running in debug only
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;
3209 1909
3210 foreach (OdePrim prim in _activeprims) 1910 int nstaticgeoms = 0;
1911 int nstaticspaces = 0;
1912 IntPtr sp;
1913
1914 for (int i = 0; i < ntopactivegeoms; i++)
3211 { 1915 {
3212 if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) 1916 sp = d.SpaceGetGeom(ActiveSpace, i);
1917 if (d.GeomIsSpace(sp))
3213 { 1918 {
3214 prim.UpdatePositionAndVelocity(); 1919 nactivespaces++;
3215 1920 nactivegeoms += d.SpaceGetNumGeoms(sp);
3216 if (SupportsNINJAJoints)
3217 SimulateActorPendingJoints(prim);
3218 } 1921 }
1922 else
1923 nactivegeoms++;
3219 } 1924 }
3220 1925
3221 if (CollectStats) 1926 for (int i = 0; i < ntopstaticgeoms; i++)
3222 m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); 1927 {
1928 sp = d.SpaceGetGeom(StaticSpace, i);
1929 if (d.GeomIsSpace(sp))
1930 {
1931 nstaticspaces++;
1932 nstaticgeoms += d.SpaceGetNumGeoms(sp);
1933 }
1934 else
1935 nstaticgeoms++;
1936 }
3223 1937
3224 //DumpJointInfo(); 1938 int ntopgeoms = d.SpaceGetNumGeoms(TopSpace);
3225 1939
1940 int totgeoms = nstaticgeoms + nactivegeoms + ngroundgeoms + 1; // one ray
1941 int nbodies = d.NTotalBodies;
1942 int ngeoms = d.NTotalGeoms;
1943*/
3226 // Finished with all sim stepping. If requested, dump world state to file for debugging. 1944 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3227 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? 1945 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3228 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? 1946 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
@@ -3241,256 +1959,26 @@ namespace OpenSim.Region.Physics.OdePlugin
3241 1959
3242 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); 1960 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3243 } 1961 }
3244 1962
3245 latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun); 1963 // think time dilation as to do with dinamic step size that we dont' have
3246 1964 // even so tell something to world
3247 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics 1965 if (nodeframes < 10) // we did the requested loops
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 {
3254 m_timeDilation = 1.0f; 1966 m_timeDilation = 1.0f;
3255 } 1967 else if (step_time > 0)
3256 else
3257 { 1968 {
3258 m_timeDilation = 100f / latertickcount; 1969 m_timeDilation = timeStep / step_time;
3259 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f); 1970 if (m_timeDilation > 1)
1971 m_timeDilation = 1;
1972 if (step_time > m_SkipFramesAtms)
1973 step_time = 0;
3260 } 1974 }
3261
3262 tickCountFrameRun = Util.EnvironmentTickCount();
3263
3264 if (CollectStats)
3265 m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick);
3266 } 1975 }
3267 1976
3268 return fps; 1977// return nodeframes * ODE_STEPSIZE; // return real simulated time
1978 return 1000 * nodeframes; // return steps for now * 1000 to keep core happy
3269 } 1979 }
3270 1980
3271 /// <summary> 1981 /// <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
3494 public override void GetResults() 1982 public override void GetResults()
3495 { 1983 {
3496 } 1984 }
@@ -3498,275 +1986,141 @@ namespace OpenSim.Region.Physics.OdePlugin
3498 public override bool IsThreaded 1986 public override bool IsThreaded
3499 { 1987 {
3500 // for now we won't be multithreaded 1988 // for now we won't be multithreaded
3501 get { return false; } 1989 get { return (false); }
3502 } 1990 }
3503 1991
3504 #region ODE Specific Terrain Fixes 1992 public float GetTerrainHeightAtXY(float x, float y)
3505 private float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3506 { 1993 {
3507 float[] returnarr = new float[262144];
3508 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3509 1994
3510 // Filling out the array into its multi-dimensional components
3511 for (int y = 0; y < WorldExtents.Y; y++)
3512 {
3513 for (int x = 0; x < WorldExtents.X; x++)
3514 {
3515 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3516 }
3517 }
3518 1995
3519 // Resize using Nearest Neighbour 1996 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
3520 1997 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
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++)
3580 {
3581 for (int x = 0; x < WorldExtents.X; x++)
3582 {
3583 resultarr2[y * 2, x * 2] = resultarr[y, x];
3584 1998
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 }
3597 }
3598 }
3599 1999
3600 //Flatten out the array 2000 IntPtr heightFieldGeom = IntPtr.Zero;
3601 int i = 0;
3602 for (int y = 0; y < 512; y++)
3603 {
3604 for (int x = 0; x < 512; x++)
3605 {
3606 if (resultarr2[y, x] <= 0)
3607 returnarr[i] = 0.0000001f;
3608 else
3609 returnarr[i] = resultarr2[y, x];
3610 2001
3611 i++; 2002 // get region map
3612 } 2003 if (!RegionTerrain.TryGetValue(new Vector3(offsetX, offsetY, 0), out heightFieldGeom))
3613 } 2004 return 0f;
3614 2005
3615 return returnarr; 2006 if (heightFieldGeom == IntPtr.Zero)
3616 } 2007 return 0f;
3617 2008
3618 private float[] ResizeTerrain512Interpolation(float[] heightMap) 2009 if (!TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
3619 { 2010 return 0f;
3620 float[] returnarr = new float[262144]; 2011
3621 float[,] resultarr = new float[512,512]; 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;
3622 2021
3623 // Filling out the array into its multi-dimensional components 2022 // integer indexs
3624 for (int y = 0; y < 256; y++) 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)
3625 { 2032 {
3626 for (int x = 0; x < 256; x++) 2033 if (x < regsize - 1)
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)
3627 { 2044 {
3628 resultarr[y, x] = heightMap[y * 256 + x]; 2045 iy = (int)y;
2046 dy = y - (float)iy;
2047 }
2048 else
2049 {
2050 iy = regsize - 2;
2051 dy = 0;
3629 } 2052 }
3630 } 2053 }
3631 2054
3632 // Resize using interpolation 2055 else
3633
3634 // This particular way is quick but it only works on a multiple of the original
3635
3636 // The idea behind this method can be described with the following diagrams
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 { 2056 {
3694 for (int x = 0; x < (int)Constants.RegionSize; x++) 2057 // we still have square fixed size regions
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 {
2067 iy = regsize - 2;
2068 dy = 0;
2069 }
2070 if (y < regsize - 1)
2071 {
2072 ix = (int)y;
2073 dx = y - (float)ix;
2074 }
2075 else
3695 { 2076 {
3696 resultarr2[y*2, x*2] = resultarr[y, x]; 2077 ix = regsize - 2;
2078 dx = 0;
2079 }
2080 }
3697 2081
3698 if (y < (int)Constants.RegionSize) 2082 float h0;
3699 { 2083 float h1;
3700 if (y + 1 < (int)Constants.RegionSize) 2084 float h2;
3701 { 2085
3702 if (x + 1 < (int)Constants.RegionSize) 2086 iy *= regsize;
3703 { 2087 iy += ix; // all indexes have iy + ix
3704 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] + 2088
3705 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4); 2089 float[] heights = TerrainHeightFieldHeights[heightFieldGeom];
3706 } 2090 /*
3707 else 2091 if ((dx + dy) <= 1.0f)
3708 {
3709 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3710 }
3711 }
3712 else
3713 {
3714 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3715 }
3716 }
3717 if (x < (int)Constants.RegionSize)
3718 {
3719 if (x + 1 < (int)Constants.RegionSize)
3720 {
3721 if (y + 1 < (int)Constants.RegionSize)
3722 {
3723 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
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 { 2092 {
3740 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] + 2093 h0 = ((float)heights[iy]); // 0,0 vertice
3741 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4); 2094 h1 = (((float)heights[iy + 1]) - h0) * dx; // 1,0 vertice minus 0,0
2095 h2 = (((float)heights[iy + regsize]) - h0) * dy; // 0,1 vertice minus 0,0
3742 } 2096 }
3743 else 2097 else
3744 { 2098 {
3745 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x]; 2099 h0 = ((float)heights[iy + regsize + 1]); // 1,1 vertice
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
3746 } 2102 }
3747 } 2103 */
3748 } 2104 h0 = ((float)heights[iy]); // 0,0 vertice
2105
2106 if ((dy > dx))
2107 {
2108 iy += regsize;
2109 h2 = (float)heights[iy]; // 0,1 vertice
2110 h1 = (h2 - h0) * dy; // 0,1 vertice minus 0,0
2111 h2 = ((float)heights[iy + 1] - h2) * dx; // 1,1 vertice minus 0,1
3749 } 2112 }
3750 //Flatten out the array 2113 else
3751 int i = 0;
3752 for (int y = 0; y < 512; y++)
3753 { 2114 {
3754 for (int x = 0; x < 512; x++) 2115 iy++;
3755 { 2116 h2 = (float)heights[iy]; // vertice 1,0
3756 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x])) 2117 h1 = (h2 - h0) * dx; // 1,0 vertice minus 0,0
3757 { 2118 h2 = (((float)heights[iy + regsize]) - h2) * dy; // 1,1 vertice minus 1,0
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 }
3764 } 2119 }
3765 2120
3766 return returnarr; 2121 return h0 + h1 + h2;
3767 } 2122 }
3768 2123
3769 #endregion
3770 2124
3771 public override void SetTerrain(float[] heightMap) 2125 public override void SetTerrain(float[] heightMap)
3772 { 2126 {
@@ -3783,78 +2137,75 @@ namespace OpenSim.Region.Physics.OdePlugin
3783 } 2137 }
3784 } 2138 }
3785 2139
3786 private void SetTerrain(float[] heightMap, Vector3 pOffset) 2140 public override void CombineTerrain(float[] heightMap, Vector3 pOffset)
3787 { 2141 {
3788 int startTime = Util.EnvironmentTickCount(); 2142 SetTerrain(heightMap, pOffset);
3789 m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", Name, pOffset); 2143 }
3790
3791 // this._heightmap[i] = (double)heightMap[i];
3792 // dbm (danx0r) -- creating a buffer zone of one extra sample all around
3793 //_origheightmap = heightMap;
3794
3795 float[] _heightmap;
3796
3797 // zero out a heightmap array float array (single dimension [flattened]))
3798 //if ((int)Constants.RegionSize == 256)
3799 // _heightmap = new float[514 * 514];
3800 //else
3801 2144
3802 _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))]; 2145 public void SetTerrain(float[] heightMap, Vector3 pOffset)
2146 {
2147 if (OdeUbitLib)
2148 UbitSetTerrain(heightMap, pOffset);
2149 else
2150 OriSetTerrain(heightMap, pOffset);
2151 }
3803 2152
3804 uint heightmapWidth = Constants.RegionSize + 1; 2153 public void OriSetTerrain(float[] heightMap, Vector3 pOffset)
3805 uint heightmapHeight = Constants.RegionSize + 1; 2154 {
2155 // assumes 1m size grid and constante size square regions
2156 // needs to know about sims around in future
3806 2157
3807 uint heightmapWidthSamples; 2158 float[] _heightmap;
3808 2159
3809 uint heightmapHeightSamples; 2160 uint heightmapWidth = Constants.RegionSize + 2;
2161 uint heightmapHeight = Constants.RegionSize + 2;
3810 2162
3811 //if (((int)Constants.RegionSize) == 256) 2163 uint heightmapWidthSamples = heightmapWidth + 1;
3812 //{ 2164 uint heightmapHeightSamples = heightmapHeight + 1;
3813 // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2;
3814 // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2;
3815 // heightmapWidth++;
3816 // heightmapHeight++;
3817 //}
3818 //else
3819 //{
3820 2165
3821 heightmapWidthSamples = (uint)Constants.RegionSize + 1; 2166 _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples];
3822 heightmapHeightSamples = (uint)Constants.RegionSize + 1;
3823 //}
3824 2167
3825 const float scale = 1.0f; 2168 const float scale = 1.0f;
3826 const float offset = 0.0f; 2169 const float offset = 0.0f;
3827 const float thickness = 0.2f; 2170 const float thickness = 10f;
3828 const int wrap = 0; 2171 const int wrap = 0;
3829 2172
3830 int regionsize = (int) Constants.RegionSize + 2; 2173 uint regionsize = Constants.RegionSize;
3831 //Double resolution 2174
3832 //if (((int)Constants.RegionSize) == 256) 2175 float hfmin = float.MaxValue;
3833 // heightMap = ResizeTerrain512Interpolation(heightMap); 2176 float hfmax = float.MinValue;
2177 float val;
2178 uint xx;
2179 uint yy;
3834 2180
2181 uint maxXXYY = regionsize - 1;
2182 // flipping map adding one margin all around so things don't fall in edges
3835 2183
3836 // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256) 2184 uint xt = 0;
3837 // regionsize = 512; 2185 xx = 0;
3838 2186
3839 float hfmin = 2000; 2187 for (uint x = 0; x < heightmapWidthSamples; x++)
3840 float hfmax = -2000;
3841
3842 for (int x = 0; x < heightmapWidthSamples; x++)
3843 { 2188 {
3844 for (int y = 0; y < heightmapHeightSamples; y++) 2189 if (x > 1 && xx < maxXXYY)
2190 xx++;
2191 yy = 0;
2192 for (uint y = 0; y < heightmapHeightSamples; y++)
3845 { 2193 {
3846 int xx = Util.Clip(x - 1, 0, regionsize - 1); 2194 if (y > 1 && y < maxXXYY)
3847 int yy = Util.Clip(y - 1, 0, regionsize - 1); 2195 yy += regionsize;
3848 2196
3849 2197 val = heightMap[yy + xx];
3850 float val= heightMap[yy * (int)Constants.RegionSize + xx]; 2198 if (val < 0.0f)
3851 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val; 2199 val = 0.0f; // no neg terrain as in chode
3852 2200 _heightmap[xt + y] = val;
3853 hfmin = (val < hfmin) ? val : hfmin; 2201
3854 hfmax = (val > hfmax) ? val : hfmax; 2202 if (hfmin > val)
2203 hfmin = val;
2204 if (hfmax < val)
2205 hfmax = val;
3855 } 2206 }
2207 xt += heightmapHeightSamples;
3856 } 2208 }
3857
3858 lock (OdeLock) 2209 lock (OdeLock)
3859 { 2210 {
3860 IntPtr GroundGeom = IntPtr.Zero; 2211 IntPtr GroundGeom = IntPtr.Zero;
@@ -3863,62 +2214,177 @@ namespace OpenSim.Region.Physics.OdePlugin
3863 RegionTerrain.Remove(pOffset); 2214 RegionTerrain.Remove(pOffset);
3864 if (GroundGeom != IntPtr.Zero) 2215 if (GroundGeom != IntPtr.Zero)
3865 { 2216 {
2217 actor_name_map.Remove(GroundGeom);
2218 d.GeomDestroy(GroundGeom);
2219
3866 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) 2220 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3867 { 2221 {
2222 TerrainHeightFieldHeightsHandlers[GroundGeom].Free();
2223 TerrainHeightFieldHeightsHandlers.Remove(GroundGeom);
3868 TerrainHeightFieldHeights.Remove(GroundGeom); 2224 TerrainHeightFieldHeights.Remove(GroundGeom);
3869 } 2225 }
3870 d.SpaceRemove(space, GroundGeom);
3871 d.GeomDestroy(GroundGeom);
3872 } 2226 }
3873
3874 } 2227 }
3875 IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); 2228 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3876 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1, 2229
3877 (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale, 2230 GCHandle _heightmaphandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned);
2231
2232 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmaphandler.AddrOfPinnedObject(), 0, heightmapWidth , heightmapHeight,
2233 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3878 offset, thickness, wrap); 2234 offset, thickness, wrap);
2235
3879 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); 2236 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3880 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1); 2237
2238 GroundGeom = d.CreateHeightfield(GroundSpace, HeightmapData, 1);
2239
3881 if (GroundGeom != IntPtr.Zero) 2240 if (GroundGeom != IntPtr.Zero)
3882 { 2241 {
3883 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land)); 2242 d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
3884 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space)); 2243 d.GeomSetCollideBits(GroundGeom, 0);
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);
3885 2256
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);
3886 } 2270 }
3887 geom_name_map[GroundGeom] = "Terrain"; 2271 }
2272 }
3888 2273
3889 d.Matrix3 R = new d.Matrix3(); 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
3890 2278
3891 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); 2279 float[] _heightmap;
3892 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); 2280
3893 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1)); 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;
3894 2291
3895 q1 = q1 * q2; 2292 float hfmin = float.MaxValue;
3896 //q1 = q1 * q3; 2293// float hfmax = float.MinValue;
3897 Vector3 v3; 2294 float val;
3898 float angle;
3899 q1.GetAxisAngle(out v3, out angle);
3900 2295
3901 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); 2296
3902 d.GeomSetRotation(GroundGeom, ref R); 2297 uint maxXXYY = regionsize - 1;
3903 d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)), (pOffset.Y + ((int)Constants.RegionSize * 0.5f)), 0); 2298 // adding one margin all around so things don't fall in edges
3904 IntPtr testGround = IntPtr.Zero; 2299
3905 if (RegionTerrain.TryGetValue(pOffset, out testGround)) 2300 uint xx;
2301 uint yy = 0;
2302 uint yt = 0;
2303
2304 for (uint y = 0; y < heightmapHeightSamples; y++)
2305 {
2306 if (y > 1 && y < maxXXYY)
2307 yy += regionsize;
2308 xx = 0;
2309 for (uint x = 0; x < heightmapWidthSamples; x++)
3906 { 2310 {
3907 RegionTerrain.Remove(pOffset); 2311 if (x > 1 && x < maxXXYY)
2312 xx++;
2313
2314 val = heightMap[yy + xx];
2315 if (val < 0.0f)
2316 val = 0.0f; // no neg terrain as in chode
2317 _heightmap[yt + x] = val;
2318
2319 if (hfmin > val)
2320 hfmin = val;
2321// if (hfmax < val)
2322// hfmax = val;
3908 } 2323 }
3909 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); 2324 yt += heightmapWidthSamples;
3910 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3911 } 2325 }
2326 lock (OdeLock)
2327 {
2328 IntPtr GroundGeom = IntPtr.Zero;
2329 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
2330 {
2331 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);
3912 2354
3913 m_log.DebugFormat( 2355 d.GeomUbitTerrainDataBuild(HeightmapData, _heightmaphandler.AddrOfPinnedObject(), 0, 1.0f,
3914 "[ODE SCENE]: Setting terrain for {0} took {1}ms", Name, Util.EnvironmentTickCountSubtract(startTime)); 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 }
2379 }
3915 } 2380 }
3916 2381
2382
3917 public override void DeleteTerrain() 2383 public override void DeleteTerrain()
3918 { 2384 {
3919 } 2385 }
3920 2386
3921 internal float GetWaterLevel() 2387 public float GetWaterLevel()
3922 { 2388 {
3923 return waterlevel; 2389 return waterlevel;
3924 } 2390 }
@@ -3927,169 +2393,252 @@ namespace OpenSim.Region.Physics.OdePlugin
3927 { 2393 {
3928 return true; 2394 return true;
3929 } 2395 }
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>();
3930 2403
3931// public override void UnCombine(PhysicsScene pScene) 2404 lock (OdeLock)
3932// { 2405 {
3933// IntPtr localGround = IntPtr.Zero; 2406 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3934//// float[] localHeightfield; 2407 {
3935// bool proceed = false; 2408 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3936// List<IntPtr> geomDestroyList = new List<IntPtr>(); 2409 {
3937// 2410 if (geom == localGround)
3938// lock (OdeLock) 2411 {
3939// { 2412// localHeightfield = TerrainHeightFieldHeights[geom];
3940// if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround)) 2413 proceed = true;
3941// { 2414 }
3942// foreach (IntPtr geom in TerrainHeightFieldHeights.Keys) 2415 else
3943// { 2416 {
3944// if (geom == localGround) 2417 geomDestroyList.Add(geom);
3945// { 2418 }
3946//// localHeightfield = TerrainHeightFieldHeights[geom]; 2419 }
3947// proceed = true; 2420
3948// } 2421 if (proceed)
3949// else 2422 {
3950// { 2423 m_worldOffset = Vector3.Zero;
3951// geomDestroyList.Add(geom); 2424 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3952// } 2425 m_parentScene = null;
3953// } 2426
3954// 2427 foreach (IntPtr g in geomDestroyList)
3955// if (proceed) 2428 {
3956// { 2429 // removingHeightField needs to be done or the garbage collector will
3957// m_worldOffset = Vector3.Zero; 2430 // collect the terrain data before we tell ODE to destroy it causing
3958// WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); 2431 // memory corruption
3959// m_parentScene = null; 2432 if (TerrainHeightFieldHeights.ContainsKey(g))
3960// 2433 {
3961// foreach (IntPtr g in geomDestroyList) 2434// float[] removingHeightField = TerrainHeightFieldHeights[g];
3962// { 2435 TerrainHeightFieldHeights.Remove(g);
3963// // removingHeightField needs to be done or the garbage collector will 2436
3964// // collect the terrain data before we tell ODE to destroy it causing 2437 if (RegionTerrain.ContainsKey(g))
3965// // memory corruption 2438 {
3966// if (TerrainHeightFieldHeights.ContainsKey(g)) 2439 RegionTerrain.Remove(g);
3967// { 2440 }
3968//// float[] removingHeightField = TerrainHeightFieldHeights[g]; 2441
3969// TerrainHeightFieldHeights.Remove(g); 2442 d.GeomDestroy(g);
3970// 2443 //removingHeightField = new float[0];
3971// if (RegionTerrain.ContainsKey(g)) 2444 }
3972// { 2445 }
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// }
3989 2446
2447 }
2448 else
2449 {
2450 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
2451 }
2452 }
2453 }
2454 }
2455*/
3990 public override void SetWaterLevel(float baseheight) 2456 public override void SetWaterLevel(float baseheight)
3991 { 2457 {
3992 waterlevel = baseheight; 2458 waterlevel = baseheight;
3993 randomizeWater(waterlevel); 2459// randomizeWater(waterlevel);
3994 } 2460 }
3995 2461/*
3996 private void randomizeWater(float baseheight) 2462 public void randomizeWater(float baseheight)
3997 { 2463 {
3998 const uint heightmapWidth = m_regionWidth + 2; 2464 const uint heightmapWidth = Constants.RegionSize + 2;
3999 const uint heightmapHeight = m_regionHeight + 2; 2465 const uint heightmapHeight = Constants.RegionSize + 2;
4000 const uint heightmapWidthSamples = m_regionWidth + 2; 2466 const uint heightmapWidthSamples = heightmapWidth + 1;
4001 const uint heightmapHeightSamples = m_regionHeight + 2; 2467 const uint heightmapHeightSamples = heightmapHeight + 1;
2468
4002 const float scale = 1.0f; 2469 const float scale = 1.0f;
4003 const float offset = 0.0f; 2470 const float offset = 0.0f;
4004 const float thickness = 2.9f;
4005 const int wrap = 0; 2471 const int wrap = 0;
4006 2472
4007 for (int i = 0; i < (258 * 258); i++) 2473 float[] _watermap = new float[heightmapWidthSamples * heightmapWidthSamples];
2474
2475 float maxheigh = float.MinValue;
2476 float minheigh = float.MaxValue;
2477 float val;
2478 for (int i = 0; i < (heightmapWidthSamples * heightmapHeightSamples); i++)
4008 { 2479 {
4009 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f); 2480
4010 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f)); 2481 val = (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;
4011 } 2487 }
4012 2488
2489 float thickness = minheigh;
2490
4013 lock (OdeLock) 2491 lock (OdeLock)
4014 { 2492 {
4015 if (WaterGeom != IntPtr.Zero) 2493 if (WaterGeom != IntPtr.Zero)
4016 { 2494 {
4017 d.SpaceRemove(space, WaterGeom); 2495 actor_name_map.Remove(WaterGeom);
2496 d.GeomDestroy(WaterGeom);
2497 d.GeomHeightfieldDataDestroy(WaterHeightmapData);
2498 WaterGeom = IntPtr.Zero;
2499 WaterHeightmapData = IntPtr.Zero;
2500 if(WaterMapHandler.IsAllocated)
2501 WaterMapHandler.Free();
4018 } 2502 }
4019 IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); 2503
4020 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight, 2504 WaterHeightmapData = d.GeomHeightfieldDataCreate();
2505
2506 WaterMapHandler = GCHandle.Alloc(_watermap, GCHandleType.Pinned);
2507
2508 d.GeomHeightfieldDataBuildSingle(WaterHeightmapData, WaterMapHandler.AddrOfPinnedObject(), 0, heightmapWidth, heightmapHeight,
4021 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale, 2509 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
4022 offset, thickness, wrap); 2510 offset, thickness, wrap);
4023 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight); 2511 d.GeomHeightfieldDataSetBounds(WaterHeightmapData, minheigh, maxheigh);
4024 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1); 2512 WaterGeom = d.CreateHeightfield(StaticSpace, WaterHeightmapData, 1);
4025 if (WaterGeom != IntPtr.Zero) 2513 if (WaterGeom != IntPtr.Zero)
4026 { 2514 {
4027 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water)); 2515 d.GeomSetCategoryBits(WaterGeom, (uint)(CollisionCategories.Water));
4028 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space)); 2516 d.GeomSetCollideBits(WaterGeom, 0);
4029 } 2517
4030 2518
4031 geom_name_map[WaterGeom] = "Water"; 2519 PhysicsActor pa = new NullPhysicsActor();
2520 pa.Name = "Water";
2521 pa.PhysicsActorType = (int)ActorTypes.Water;
4032 2522
4033 d.Matrix3 R = new d.Matrix3(); 2523 actor_name_map[WaterGeom] = pa;
2524// geom_name_map[WaterGeom] = "Water";
4034 2525
4035 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); 2526 d.Matrix3 R = new d.Matrix3();
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));
4038 2527
4039 q1 = q1 * q2; 2528 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
4040 //q1 = q1 * q3; 2529 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
4041 Vector3 v3;
4042 float angle;
4043 q1.GetAxisAngle(out v3, out angle);
4044 2530
4045 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); 2531 q1 = q1 * q2;
4046 d.GeomSetRotation(WaterGeom, ref R); 2532 Vector3 v3;
4047 d.GeomSetPosition(WaterGeom, 128, 128, 0); 2533 float angle;
2534 q1.GetAxisAngle(out v3, out angle);
2535
2536 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
2537 d.GeomSetRotation(WaterGeom, ref R);
2538 d.GeomSetPosition(WaterGeom, (float)Constants.RegionSize * 0.5f, (float)Constants.RegionSize * 0.5f, 0);
2539 }
4048 } 2540 }
4049 } 2541 }
4050 2542*/
4051 public override void Dispose() 2543 public override void Dispose()
4052 { 2544 {
4053 _worldInitialized = false; 2545 if (m_meshWorker != null)
4054 2546 m_meshWorker.Stop();
4055 m_rayCastManager.Dispose();
4056 m_rayCastManager = null;
4057 2547
4058 lock (OdeLock) 2548 lock (OdeLock)
4059 { 2549 {
2550 m_rayCastManager.Dispose();
2551 m_rayCastManager = null;
2552
4060 lock (_prims) 2553 lock (_prims)
4061 { 2554 {
2555 ChangesQueue.Clear();
4062 foreach (OdePrim prm in _prims) 2556 foreach (OdePrim prm in _prims)
4063 { 2557 {
4064 RemovePrim(prm); 2558 prm.DoAChange(changes.Remove, null);
2559 _collisionEventPrim.Remove(prm);
4065 } 2560 }
2561 _prims.Clear();
2562 }
2563
2564 OdeCharacter[] chtorem;
2565 lock (_characters)
2566 {
2567 chtorem = new OdeCharacter[_characters.Count];
2568 _characters.CopyTo(chtorem);
4066 } 2569 }
4067 2570
4068 //foreach (OdeCharacter act in _characters) 2571 ChangesQueue.Clear();
4069 //{ 2572 foreach (OdeCharacter ch in chtorem)
4070 //RemoveAvatar(act); 2573 ch.DoAChange(changes.Remove, null);
4071 //} 2574
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
4072 d.WorldDestroy(world); 2615 d.WorldDestroy(world);
2616 world = IntPtr.Zero;
4073 //d.CloseODE(); 2617 //d.CloseODE();
4074 } 2618 }
4075
4076 } 2619 }
4077 2620
4078 public override Dictionary<uint, float> GetTopColliders() 2621 public override Dictionary<uint, float> GetTopColliders()
4079 { 2622 {
4080 Dictionary<uint, float> topColliders; 2623 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
4081 2624 int cnt = 0;
4082 lock (_prims) 2625 lock (_prims)
4083 { 2626 {
4084 List<OdePrim> orderedPrims = new List<OdePrim>(_prims); 2627 foreach (OdePrim prm in _prims)
4085 orderedPrims.OrderByDescending(p => p.CollisionScore).Take(25); 2628 {
4086 topColliders = orderedPrims.ToDictionary(p => p.LocalID, p => p.CollisionScore); 2629 if (prm.CollisionScore > 0)
4087 2630 {
4088 foreach (OdePrim p in _prims) 2631 returncolliders.Add(prm.LocalID, prm.CollisionScore);
4089 p.CollisionScore = 0; 2632 cnt++;
2633 prm.CollisionScore = 0f;
2634 if (cnt > 25)
2635 {
2636 break;
2637 }
2638 }
2639 }
4090 } 2640 }
4091 2641 return returncolliders;
4092 return topColliders;
4093 } 2642 }
4094 2643
4095 public override bool SupportsRayCast() 2644 public override bool SupportsRayCast()
@@ -4113,6 +2662,7 @@ namespace OpenSim.Region.Physics.OdePlugin
4113 } 2662 }
4114 } 2663 }
4115 2664
2665 // don't like this
4116 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) 2666 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
4117 { 2667 {
4118 ContactResult[] ourResults = null; 2668 ContactResult[] ourResults = null;
@@ -4129,182 +2679,107 @@ namespace OpenSim.Region.Physics.OdePlugin
4129 waitTime++; 2679 waitTime++;
4130 } 2680 }
4131 if (ourResults == null) 2681 if (ourResults == null)
4132 return new List<ContactResult> (); 2682 return new List<ContactResult>();
4133 return new List<ContactResult>(ourResults); 2683 return new List<ContactResult>(ourResults);
4134 } 2684 }
4135 2685
4136#if USE_DRAWSTUFF 2686 public override bool SuportsRaycastWorldFiltered()
4137 // Keyboard callback
4138 public void command(int cmd)
4139 { 2687 {
4140 IntPtr geom; 2688 return true;
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 }
4198 } 2689 }
4199 2690
4200 public void step(int pause) 2691 public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
4201 { 2692 {
4202 2693 object SyncObject = new object();
4203 ds.SetColor(1.0f, 1.0f, 0.0f); 2694 List<ContactResult> ourresults = new List<ContactResult>();
4204 ds.SetTexture(ds.Texture.Wood); 2695
4205 lock (_prims) 2696 RayCallback retMethod = delegate(List<ContactResult> results)
4206 { 2697 {
4207 foreach (OdePrim prm in _prims) 2698 lock (SyncObject)
4208 { 2699 {
4209 //IntPtr body = d.GeomGetBody(prm.prim_geom); 2700 ourresults = results;
4210 if (prm.prim_geom != IntPtr.Zero) 2701 Monitor.PulseAll(SyncObject);
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 }
4228 } 2702 }
4229 } 2703 };
4230 ds.SetColor(1.0f, 0.0f, 0.0f);
4231 2704
4232 foreach (OdeCharacter chr in _characters) 2705 lock (SyncObject)
4233 { 2706 {
4234 if (chr.Shell != IntPtr.Zero) 2707 m_rayCastManager.QueueRequest(position, direction, length, Count,filter, retMethod);
4235 { 2708 if (!Monitor.Wait(SyncObject, 500))
4236 IntPtr body = d.GeomGetBody(chr.Shell); 2709 return null;
4237 2710 else
4238 d.Vector3 pos; 2711 return ourresults;
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 }
4254 } 2712 }
4255 } 2713 }
4256 2714
4257 public void start(int unused) 2715 public override void RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
4258 { 2716 {
4259 ds.SetViewpoint(ref xyz, ref hpr); 2717 if (retMethod != null && actor !=null)
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 }
4260 } 2730 }
4261#endif
4262 2731
4263 public override Dictionary<string, float> GetStats() 2732 public override void RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
4264 { 2733 {
4265 if (!CollectStats) 2734 if (retMethod != null && actor != null)
4266 return null;
4267
4268 Dictionary<string, float> returnStats;
4269
4270 lock (OdeLock)
4271 { 2735 {
4272 returnStats = new Dictionary<string, float>(m_stats); 2736 IntPtr geom;
4273 2737 if (actor is OdePrim)
4274 // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by 2738 geom = ((OdePrim)actor).prim_geom;
4275 // 3 from the SimStatsReporter. 2739 else if (actor is OdeCharacter)
4276 returnStats[ODETotalAvatarsStatName] = _characters.Count * 3; 2740 geom = ((OdePrim)actor).prim_geom;
4277 returnStats[ODETotalPrimsStatName] = _prims.Count * 3; 2741 else
4278 returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3; 2742 return;
2743 if (geom == IntPtr.Zero)
2744 return;
4279 2745
4280 InitializeExtraStats(); 2746 m_rayCastManager.QueueRequest(geom,position, direction, length, Count, retMethod);
4281 } 2747 }
4282
4283 returnStats[ODEOtherCollisionFrameMsStatName]
4284 = returnStats[ODEOtherCollisionFrameMsStatName]
4285 - returnStats[ODENativeSpaceCollisionFrameMsStatName]
4286 - returnStats[ODENativeGeomCollisionFrameMsStatName];
4287
4288 return returnStats;
4289 } 2748 }
4290 2749
4291 private void InitializeExtraStats() 2750 // don't like this
2751 public override List<ContactResult> RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count)
4292 { 2752 {
4293 m_stats[ODETotalFrameMsStatName] = 0; 2753 if (actor != null)
4294 m_stats[ODEAvatarTaintMsStatName] = 0; 2754 {
4295 m_stats[ODEPrimTaintMsStatName] = 0; 2755 IntPtr geom;
4296 m_stats[ODEAvatarForcesFrameMsStatName] = 0; 2756 if (actor is OdePrim)
4297 m_stats[ODEPrimForcesFrameMsStatName] = 0; 2757 geom = ((OdePrim)actor).prim_geom;
4298 m_stats[ODERaycastingFrameMsStatName] = 0; 2758 else if (actor is OdeCharacter)
4299 m_stats[ODENativeStepFrameMsStatName] = 0; 2759 geom = ((OdePrim)actor).prim_geom;
4300 m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0; 2760 else
4301 m_stats[ODENativeGeomCollisionFrameMsStatName] = 0; 2761 return new List<ContactResult>();
4302 m_stats[ODEOtherCollisionFrameMsStatName] = 0; 2762 if (geom == IntPtr.Zero)
4303 m_stats[ODECollisionNotificationFrameMsStatName] = 0; 2763 return new List<ContactResult>();
4304 m_stats[ODEAvatarContactsStatsName] = 0; 2764
4305 m_stats[ODEPrimContactsStatName] = 0; 2765 ContactResult[] ourResults = null;
4306 m_stats[ODEAvatarUpdateFrameMsStatName] = 0; 2766 RayCallback retMethod = delegate(List<ContactResult> results)
4307 m_stats[ODEPrimUpdateFrameMsStatName] = 0; 2767 {
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>();
4308 } 2783 }
4309 } 2784 }
4310} \ No newline at end of file 2785}