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