diff options
author | UbitUmarov | 2012-04-16 16:16:55 +0100 |
---|---|---|
committer | UbitUmarov | 2012-04-16 16:16:55 +0100 |
commit | 86a2169d7343825c74ae271f637002377b92b438 (patch) | |
tree | 5bfc66b130edcacc738d3f4e8b4efa854a37fe7e /OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs | |
parent | Use chode character actor.SetMomentum() to force full restore Velocity in sce... (diff) | |
download | opensim-SC-86a2169d7343825c74ae271f637002377b92b438.zip opensim-SC-86a2169d7343825c74ae271f637002377b92b438.tar.gz opensim-SC-86a2169d7343825c74ae271f637002377b92b438.tar.bz2 opensim-SC-86a2169d7343825c74ae271f637002377b92b438.tar.xz |
ubitODE + physmanager: - Revised use of ODE collisions categories and bits(flags) for better use as filters together with top spaces (for example physical prims are on topactivespace and not physical are on topstaticspace) - Added new world raycast with filters. This blocks calling thread with a timeout of 500ms waiting for heartbeat ode thread signal job done. - Don't let ode bodies being disabled for 2 long except for vehicles. This is necessary to detect when the object is at rest at top of other and that is removed. Assume that vehicles can be enabled by used action.
Diffstat (limited to 'OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs')
-rw-r--r-- | OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs | 326 |
1 files changed, 243 insertions, 83 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs index 4b3f83b..e66580d 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs | |||
@@ -30,10 +30,11 @@ using System.Collections.Generic; | |||
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Runtime.InteropServices; | 31 | using System.Runtime.InteropServices; |
32 | using System.Text; | 32 | using System.Text; |
33 | using OpenMetaverse; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Region.Physics.Manager; | 34 | using OpenSim.Region.Physics.Manager; |
35 | using OdeAPI; | 35 | using OdeAPI; |
36 | using log4net; | 36 | using log4net; |
37 | using OpenMetaverse; | ||
37 | 38 | ||
38 | namespace OpenSim.Region.Physics.OdePlugin | 39 | namespace OpenSim.Region.Physics.OdePlugin |
39 | { | 40 | { |
@@ -54,9 +55,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
54 | /// </summary> | 55 | /// </summary> |
55 | private OdeScene m_scene; | 56 | private OdeScene m_scene; |
56 | 57 | ||
57 | IntPtr ray; | 58 | IntPtr ray; // the ray. we only need one for our lifetime |
58 | 59 | ||
59 | private const int ColisionContactGeomsPerTest = 5; | 60 | private const int ColisionContactGeomsPerTest = 5; |
61 | private const int DefaultMaxCount = 25; | ||
62 | private const int MaxTimePerCallMS = 30; | ||
60 | 63 | ||
61 | /// <summary> | 64 | /// <summary> |
62 | /// ODE near callback delegate | 65 | /// ODE near callback delegate |
@@ -64,19 +67,22 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
64 | private d.NearCallback nearCallback; | 67 | private d.NearCallback nearCallback; |
65 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 68 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
66 | private List<ContactResult> m_contactResults = new List<ContactResult>(); | 69 | private List<ContactResult> m_contactResults = new List<ContactResult>(); |
70 | private RayFilterFlags CurrentRayFilter; | ||
71 | private int CurrentMaxCount; | ||
67 | 72 | ||
68 | public ODERayCastRequestManager(OdeScene pScene) | 73 | public ODERayCastRequestManager(OdeScene pScene) |
69 | { | 74 | { |
70 | m_scene = pScene; | 75 | m_scene = pScene; |
71 | nearCallback = near; | 76 | nearCallback = near; |
72 | ray = d.CreateRay(IntPtr.Zero, 1.0f); | 77 | ray = d.CreateRay(IntPtr.Zero, 1.0f); |
78 | d.GeomSetCategoryBits(ray,0); | ||
73 | } | 79 | } |
74 | 80 | ||
75 | /// <summary> | 81 | /// <summary> |
76 | /// Queues a raycast | 82 | /// Queues request for a raycast to all world |
77 | /// </summary> | 83 | /// </summary> |
78 | /// <param name="position">Origin of Ray</param> | 84 | /// <param name="position">Origin of Ray</param> |
79 | /// <param name="direction">Ray normal</param> | 85 | /// <param name="direction">Ray direction</param> |
80 | /// <param name="length">Ray length</param> | 86 | /// <param name="length">Ray length</param> |
81 | /// <param name="retMethod">Return method to send the results</param> | 87 | /// <param name="retMethod">Return method to send the results</param> |
82 | public void QueueRequest(Vector3 position, Vector3 direction, float length, RayCallback retMethod) | 88 | public void QueueRequest(Vector3 position, Vector3 direction, float length, RayCallback retMethod) |
@@ -84,14 +90,22 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
84 | ODERayRequest req = new ODERayRequest(); | 90 | ODERayRequest req = new ODERayRequest(); |
85 | req.geom = IntPtr.Zero; | 91 | req.geom = IntPtr.Zero; |
86 | req.callbackMethod = retMethod; | 92 | req.callbackMethod = retMethod; |
87 | req.Count = 0; | 93 | req.Count = DefaultMaxCount; |
88 | req.length = length; | 94 | req.length = length; |
89 | req.Normal = direction; | 95 | req.Normal = direction; |
90 | req.Origin = position; | 96 | req.Origin = position; |
97 | req.filter = RayFilterFlags.AllButLand; | ||
91 | 98 | ||
92 | m_PendingRequests.Enqueue(req); | 99 | m_PendingRequests.Enqueue(req); |
93 | } | 100 | } |
94 | 101 | ||
102 | /// <summary> | ||
103 | /// Queues request for a raycast to particular part | ||
104 | /// </summary> | ||
105 | /// <param name="position">Origin of Ray</param> | ||
106 | /// <param name="direction">Ray direction</param> | ||
107 | /// <param name="length">Ray length</param> | ||
108 | /// <param name="retMethod">Return method to send the results</param> | ||
95 | public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, RayCallback retMethod) | 109 | public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, RayCallback retMethod) |
96 | { | 110 | { |
97 | ODERayRequest req = new ODERayRequest(); | 111 | ODERayRequest req = new ODERayRequest(); |
@@ -100,7 +114,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
100 | req.length = length; | 114 | req.length = length; |
101 | req.Normal = direction; | 115 | req.Normal = direction; |
102 | req.Origin = position; | 116 | req.Origin = position; |
103 | req.Count = 0; | 117 | req.Count = DefaultMaxCount; |
118 | req.filter = RayFilterFlags.AllButLand; | ||
104 | 119 | ||
105 | m_PendingRequests.Enqueue(req); | 120 | m_PendingRequests.Enqueue(req); |
106 | } | 121 | } |
@@ -110,10 +125,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
110 | ODERayRequest req = new ODERayRequest(); | 125 | ODERayRequest req = new ODERayRequest(); |
111 | req.geom = IntPtr.Zero; | 126 | req.geom = IntPtr.Zero; |
112 | req.callbackMethod = retMethod; | 127 | req.callbackMethod = retMethod; |
113 | req.Count = 0; | 128 | req.Count = DefaultMaxCount; |
114 | req.length = length; | 129 | req.length = length; |
115 | req.Normal = direction; | 130 | req.Normal = direction; |
116 | req.Origin = position; | 131 | req.Origin = position; |
132 | req.filter = RayFilterFlags.AllButLand; | ||
117 | 133 | ||
118 | m_PendingRequests.Enqueue(req); | 134 | m_PendingRequests.Enqueue(req); |
119 | } | 135 | } |
@@ -126,7 +142,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
126 | req.length = length; | 142 | req.length = length; |
127 | req.Normal = direction; | 143 | req.Normal = direction; |
128 | req.Origin = position; | 144 | req.Origin = position; |
129 | req.Count = 0; | 145 | req.Count = DefaultMaxCount; |
146 | req.filter = RayFilterFlags.AllButLand; | ||
130 | 147 | ||
131 | m_PendingRequests.Enqueue(req); | 148 | m_PendingRequests.Enqueue(req); |
132 | } | 149 | } |
@@ -148,6 +165,22 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
148 | req.Normal = direction; | 165 | req.Normal = direction; |
149 | req.Origin = position; | 166 | req.Origin = position; |
150 | req.Count = count; | 167 | req.Count = count; |
168 | req.filter = RayFilterFlags.AllButLand; | ||
169 | |||
170 | m_PendingRequests.Enqueue(req); | ||
171 | } | ||
172 | |||
173 | |||
174 | public void QueueRequest(Vector3 position, Vector3 direction, float length, int count,RayFilterFlags filter , RayCallback retMethod) | ||
175 | { | ||
176 | ODERayRequest req = new ODERayRequest(); | ||
177 | req.geom = IntPtr.Zero; | ||
178 | req.callbackMethod = retMethod; | ||
179 | req.length = length; | ||
180 | req.Normal = direction; | ||
181 | req.Origin = position; | ||
182 | req.Count = count; | ||
183 | req.filter = filter; | ||
151 | 184 | ||
152 | m_PendingRequests.Enqueue(req); | 185 | m_PendingRequests.Enqueue(req); |
153 | } | 186 | } |
@@ -161,6 +194,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
161 | req.Normal = direction; | 194 | req.Normal = direction; |
162 | req.Origin = position; | 195 | req.Origin = position; |
163 | req.Count = count; | 196 | req.Count = count; |
197 | req.filter = RayFilterFlags.AllButLand; | ||
164 | 198 | ||
165 | m_PendingRequests.Enqueue(req); | 199 | m_PendingRequests.Enqueue(req); |
166 | } | 200 | } |
@@ -174,6 +208,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
174 | req.Normal = direction; | 208 | req.Normal = direction; |
175 | req.Origin = position; | 209 | req.Origin = position; |
176 | req.Count = count; | 210 | req.Count = count; |
211 | req.filter = RayFilterFlags.AllButLand; | ||
177 | 212 | ||
178 | m_PendingRequests.Enqueue(req); | 213 | m_PendingRequests.Enqueue(req); |
179 | } | 214 | } |
@@ -187,6 +222,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
187 | req.Normal = direction; | 222 | req.Normal = direction; |
188 | req.Origin = position; | 223 | req.Origin = position; |
189 | req.Count = count; | 224 | req.Count = count; |
225 | req.filter = RayFilterFlags.AllButLand; | ||
190 | 226 | ||
191 | m_PendingRequests.Enqueue(req); | 227 | m_PendingRequests.Enqueue(req); |
192 | } | 228 | } |
@@ -197,63 +233,104 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
197 | /// <returns>Time in MS the raycasts took to process.</returns> | 233 | /// <returns>Time in MS the raycasts took to process.</returns> |
198 | public int ProcessQueuedRequests() | 234 | public int ProcessQueuedRequests() |
199 | { | 235 | { |
200 | int time = System.Environment.TickCount; | ||
201 | 236 | ||
202 | if (m_PendingRequests.Count <= 0) | 237 | if (m_PendingRequests.Count <= 0) |
203 | return 0; | 238 | return 0; |
204 | 239 | ||
205 | if (m_scene.ContactgeomsArray == IntPtr.Zero) // oops something got wrong or scene isn't ready still | 240 | if (m_scene.ContactgeomsArray == IntPtr.Zero || ray == IntPtr.Zero) |
241 | // oops something got wrong or scene isn't ready still | ||
206 | { | 242 | { |
207 | m_PendingRequests.Clear(); | 243 | m_PendingRequests.Clear(); |
208 | return 0; | 244 | return 0; |
209 | } | 245 | } |
210 | 246 | ||
211 | ODERayRequest req; | 247 | int time = Util.EnvironmentTickCount(); |
212 | 248 | ||
213 | int i = 50; // arbitary limit of processed tests per frame | 249 | ODERayRequest req; |
250 | int closestHit; | ||
251 | int backfacecull; | ||
252 | CollisionCategories catflags; | ||
214 | 253 | ||
215 | while(m_PendingRequests.Dequeue(out req)) | 254 | while (m_PendingRequests.Dequeue(out req)) |
216 | { | 255 | { |
217 | if (req.geom == IntPtr.Zero) | 256 | if (req.callbackMethod != null) |
218 | doSpaceRay(req); | 257 | { |
219 | else | 258 | CurrentRayFilter = req.filter; |
220 | doGeomRay(req); | 259 | CurrentMaxCount = req.Count; |
221 | if(--i < 0) | 260 | |
222 | break; | 261 | closestHit = ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0 ? 0 : 1); |
262 | backfacecull = ((CurrentRayFilter & RayFilterFlags.BackFaceCull) == 0 ? 0 : 1); | ||
263 | |||
264 | d.GeomRaySetLength(ray, req.length); | ||
265 | d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); | ||
266 | d.GeomRaySetParams(ray, 0, backfacecull); | ||
267 | d.GeomRaySetClosestHit(ray, closestHit); | ||
268 | |||
269 | if (req.callbackMethod is RaycastCallback) | ||
270 | // if we only want one get only one per colision pair saving memory | ||
271 | CurrentRayFilter |= RayFilterFlags.ClosestHit; | ||
272 | |||
273 | if (req.geom == IntPtr.Zero) | ||
274 | { | ||
275 | // translate ray filter to colision flags | ||
276 | catflags = 0; | ||
277 | if ((CurrentRayFilter & RayFilterFlags.volumedtc) != 0) | ||
278 | catflags |= CollisionCategories.VolumeDtc; | ||
279 | if ((CurrentRayFilter & RayFilterFlags.phantom) != 0) | ||
280 | catflags |= CollisionCategories.Phantom; | ||
281 | if ((CurrentRayFilter & RayFilterFlags.agent) != 0) | ||
282 | catflags |= CollisionCategories.Character; | ||
283 | if ((CurrentRayFilter & RayFilterFlags.PrimsNonPhantom) != 0) | ||
284 | catflags |= CollisionCategories.Geom; | ||
285 | if ((CurrentRayFilter & RayFilterFlags.land) != 0) | ||
286 | catflags |= CollisionCategories.Land; | ||
287 | if ((CurrentRayFilter & RayFilterFlags.water) != 0) | ||
288 | catflags |= CollisionCategories.Water; | ||
289 | |||
290 | if (catflags != 0) | ||
291 | doSpaceRay(req); | ||
292 | } | ||
293 | else | ||
294 | { | ||
295 | // if we select a geom don't use filters | ||
296 | d.GeomSetCollideBits(ray, (uint)CollisionCategories.All); | ||
297 | doGeomRay(req); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | if (Util.EnvironmentTickCountSubtract(time) > MaxTimePerCallMS) | ||
302 | break; | ||
223 | } | 303 | } |
224 | 304 | ||
225 | lock (m_contactResults) | 305 | lock (m_contactResults) |
226 | m_contactResults.Clear(); | 306 | m_contactResults.Clear(); |
227 | 307 | ||
228 | return System.Environment.TickCount - time; | 308 | return Util.EnvironmentTickCountSubtract(time); |
229 | } | 309 | } |
230 | /// <summary> | 310 | /// <summary> |
231 | /// Method that actually initiates the raycast with full top space | 311 | /// Method that actually initiates the raycast with spaces |
232 | /// </summary> | 312 | /// </summary> |
233 | /// <param name="req"></param> | 313 | /// <param name="req"></param> |
234 | private void doSpaceRay(ODERayRequest req) | 314 | /// |
235 | { | ||
236 | // Create the ray | ||
237 | // IntPtr ray = d.CreateRay(m_scene.TopSpace, req.length); | ||
238 | d.GeomRaySetLength(ray, req.length); | ||
239 | d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); | ||
240 | 315 | ||
241 | // Collide test | 316 | private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhanton; |
242 | d.SpaceCollide2(m_scene.TopSpace, ray, IntPtr.Zero, nearCallback); | 317 | private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; |
243 | |||
244 | // Remove Ray | ||
245 | // d.GeomDestroy(ray); | ||
246 | 318 | ||
247 | if (req.callbackMethod == null) | 319 | private void doSpaceRay(ODERayRequest req) |
248 | return; | 320 | { |
321 | // Collide tests | ||
322 | if ((CurrentRayFilter & FilterActiveSpace) != 0) | ||
323 | d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback); | ||
324 | if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount)) | ||
325 | d.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback); | ||
249 | 326 | ||
250 | if (req.callbackMethod is RaycastCallback) | 327 | if (req.callbackMethod is RaycastCallback) |
251 | { | 328 | { |
252 | // Define default results | 329 | // Define default results |
253 | bool hitYN = false; | 330 | bool hitYN = false; |
254 | uint hitConsumerID = 0; | 331 | uint hitConsumerID = 0; |
255 | float distance = 999999999999f; | 332 | float distance = float.MaxValue; |
256 | Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f); | 333 | Vector3 closestcontact = Vector3.Zero; |
257 | Vector3 snormal = Vector3.Zero; | 334 | Vector3 snormal = Vector3.Zero; |
258 | 335 | ||
259 | // Find closest contact and object. | 336 | // Find closest contact and object. |
@@ -261,25 +338,30 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
261 | { | 338 | { |
262 | foreach (ContactResult cResult in m_contactResults) | 339 | foreach (ContactResult cResult in m_contactResults) |
263 | { | 340 | { |
264 | if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact)) | 341 | if(cResult.Depth < distance) |
265 | { | 342 | { |
266 | closestcontact = cResult.Pos; | 343 | closestcontact = cResult.Pos; |
267 | hitConsumerID = cResult.ConsumerID; | 344 | hitConsumerID = cResult.ConsumerID; |
268 | distance = cResult.Depth; | 345 | distance = cResult.Depth; |
269 | hitYN = true; | ||
270 | snormal = cResult.Normal; | 346 | snormal = cResult.Normal; |
271 | } | 347 | } |
272 | } | 348 | } |
273 | m_contactResults.Clear(); | 349 | m_contactResults.Clear(); |
274 | } | 350 | } |
275 | 351 | ||
352 | if (distance > 0 && distance < float.MaxValue) | ||
353 | hitYN = true; | ||
276 | ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal); | 354 | ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal); |
277 | } | 355 | } |
278 | else | 356 | else |
279 | { | 357 | { |
280 | ((RayCallback)req.callbackMethod)(m_contactResults); | 358 | List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count); |
281 | lock (m_PendingRequests) | 359 | lock (m_PendingRequests) |
360 | { | ||
361 | cresult.AddRange(m_contactResults); | ||
282 | m_contactResults.Clear(); | 362 | m_contactResults.Clear(); |
363 | } | ||
364 | ((RayCallback)req.callbackMethod)(cresult); | ||
283 | } | 365 | } |
284 | } | 366 | } |
285 | 367 | ||
@@ -289,27 +371,16 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
289 | /// <param name="req"></param> | 371 | /// <param name="req"></param> |
290 | private void doGeomRay(ODERayRequest req) | 372 | private void doGeomRay(ODERayRequest req) |
291 | { | 373 | { |
292 | // Create the ray | ||
293 | // IntPtr ray = d.CreateRay(m_scene.TopSpace, req.length); | ||
294 | d.GeomRaySetLength(ray, req.length); | ||
295 | d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); | ||
296 | |||
297 | // Collide test | 374 | // Collide test |
298 | d.SpaceCollide2(req.geom, ray, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test | 375 | d.SpaceCollide2(ray, req.geom, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test |
299 | |||
300 | // Remove Ray | ||
301 | // d.GeomDestroy(ray); | ||
302 | |||
303 | if (req.callbackMethod == null) | ||
304 | return; | ||
305 | 376 | ||
306 | if (req.callbackMethod is RaycastCallback) | 377 | if (req.callbackMethod is RaycastCallback) |
307 | { | 378 | { |
308 | // Define default results | 379 | // Define default results |
309 | bool hitYN = false; | 380 | bool hitYN = false; |
310 | uint hitConsumerID = 0; | 381 | uint hitConsumerID = 0; |
311 | float distance = 999999999999f; | 382 | float distance = float.MaxValue; |
312 | Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f); | 383 | Vector3 closestcontact = Vector3.Zero; |
313 | Vector3 snormal = Vector3.Zero; | 384 | Vector3 snormal = Vector3.Zero; |
314 | 385 | ||
315 | // Find closest contact and object. | 386 | // Find closest contact and object. |
@@ -317,25 +388,31 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
317 | { | 388 | { |
318 | foreach (ContactResult cResult in m_contactResults) | 389 | foreach (ContactResult cResult in m_contactResults) |
319 | { | 390 | { |
320 | if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact)) | 391 | if(cResult.Depth < distance ) |
321 | { | 392 | { |
322 | closestcontact = cResult.Pos; | 393 | closestcontact = cResult.Pos; |
323 | hitConsumerID = cResult.ConsumerID; | 394 | hitConsumerID = cResult.ConsumerID; |
324 | distance = cResult.Depth; | 395 | distance = cResult.Depth; |
325 | hitYN = true; | ||
326 | snormal = cResult.Normal; | 396 | snormal = cResult.Normal; |
327 | } | 397 | } |
328 | } | 398 | } |
329 | m_contactResults.Clear(); | 399 | m_contactResults.Clear(); |
330 | } | 400 | } |
331 | 401 | ||
402 | if (distance > 0 && distance < float.MaxValue) | ||
403 | hitYN = true; | ||
404 | |||
332 | ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal); | 405 | ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal); |
333 | } | 406 | } |
334 | else | 407 | else |
335 | { | 408 | { |
336 | ((RayCallback)req.callbackMethod)(m_contactResults); | 409 | List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count); |
337 | lock (m_PendingRequests) | 410 | lock (m_PendingRequests) |
411 | { | ||
412 | cresult.AddRange(m_contactResults); | ||
338 | m_contactResults.Clear(); | 413 | m_contactResults.Clear(); |
414 | } | ||
415 | ((RayCallback)req.callbackMethod)(cresult); | ||
339 | } | 416 | } |
340 | } | 417 | } |
341 | 418 | ||
@@ -350,20 +427,16 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
350 | return true; | 427 | return true; |
351 | } | 428 | } |
352 | 429 | ||
353 | // This is the standard Near. g2 is the ray | 430 | // This is the standard Near. g1 is the ray |
354 | private void near(IntPtr space, IntPtr g1, IntPtr g2) | 431 | private void near(IntPtr space, IntPtr g1, IntPtr g2) |
355 | { | 432 | { |
356 | //Don't test against heightfield Geom, or you'll be sorry! | 433 | if (g2 == IntPtr.Zero || g1 == g2) |
357 | // Exclude heightfield geom | ||
358 | |||
359 | if (g1 == IntPtr.Zero || g1 == g2) | ||
360 | return; | 434 | return; |
361 | 435 | ||
362 | if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass) | 436 | if (m_contactResults.Count >= CurrentMaxCount) |
363 | return; | 437 | return; |
364 | 438 | ||
365 | // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms. | 439 | if (d.GeomIsSpace(g2)) |
366 | if (d.GeomIsSpace(g1)) | ||
367 | { | 440 | { |
368 | try | 441 | try |
369 | { | 442 | { |
@@ -381,10 +454,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
381 | { | 454 | { |
382 | count = d.CollidePtr(g1, g2, ColisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); | 455 | count = d.CollidePtr(g1, g2, ColisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); |
383 | } | 456 | } |
384 | catch (SEHException) | ||
385 | { | ||
386 | m_log.Error("[PHYSICS Ray]: 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."); | ||
387 | } | ||
388 | catch (Exception e) | 457 | catch (Exception e) |
389 | { | 458 | { |
390 | m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message); | 459 | m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message); |
@@ -394,31 +463,116 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
394 | if (count == 0) | 463 | if (count == 0) |
395 | return; | 464 | return; |
396 | 465 | ||
397 | PhysicsActor p1 = null; | 466 | uint ID = 0; |
467 | PhysicsActor p2 = null; | ||
468 | |||
469 | m_scene.actor_name_map.TryGetValue(g2, out p2); | ||
470 | |||
471 | if (p2 == null) | ||
472 | { | ||
473 | string name; | ||
474 | |||
475 | if (!m_scene.geom_name_map.TryGetValue(g2, out name)) | ||
476 | return; | ||
477 | |||
478 | if (name == "Terrain") | ||
479 | { | ||
480 | // land colision | ||
481 | if ((CurrentRayFilter & RayFilterFlags.land) == 0) | ||
482 | return; | ||
483 | } | ||
484 | else if (name == "Water") | ||
485 | { | ||
486 | if ((CurrentRayFilter & RayFilterFlags.water) == 0) | ||
487 | return; | ||
488 | } | ||
489 | else | ||
490 | return; | ||
491 | } | ||
492 | else | ||
493 | { | ||
494 | if (p2 is OdePrim) | ||
495 | { | ||
496 | RayFilterFlags thisFlags; | ||
497 | |||
498 | if (p2.IsPhysical) | ||
499 | thisFlags = RayFilterFlags.physical; | ||
500 | else | ||
501 | thisFlags = RayFilterFlags.nonphysical; | ||
398 | 502 | ||
399 | if (g1 != IntPtr.Zero) | 503 | if (p2.Phantom) |
400 | m_scene.actor_name_map.TryGetValue(g1, out p1); | 504 | thisFlags |= RayFilterFlags.phantom; |
505 | |||
506 | if (p2.IsVolumeDtc) | ||
507 | thisFlags |= RayFilterFlags.volumedtc; | ||
508 | |||
509 | if ((thisFlags & CurrentRayFilter) == 0) | ||
510 | return; | ||
511 | |||
512 | ID = ((OdePrim)p2).m_localID; | ||
513 | } | ||
514 | else if (p2 is OdeCharacter) | ||
515 | { | ||
516 | if ((CurrentRayFilter & RayFilterFlags.agent) == 0) | ||
517 | return; | ||
518 | else | ||
519 | ID = ((OdeCharacter)p2).m_localID; | ||
520 | } | ||
521 | else //?? | ||
522 | return; | ||
523 | } | ||
401 | 524 | ||
402 | d.ContactGeom curcontact = new d.ContactGeom(); | 525 | d.ContactGeom curcontact = new d.ContactGeom(); |
403 | // Loop over contacts, build results. | 526 | |
404 | for (int i = 0; i < count; i++) | 527 | // closestHit for now only works for meshs, so must do it for others |
528 | if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0) | ||
405 | { | 529 | { |
406 | if (!GetCurContactGeom(i, ref curcontact)) | 530 | // Loop all contacts, build results. |
407 | break; | 531 | for (int i = 0; i < count; i++) |
408 | if (p1 != null) { | 532 | { |
409 | if (p1 is OdePrim) | 533 | if (!GetCurContactGeom(i, ref curcontact)) |
534 | break; | ||
535 | |||
536 | ContactResult collisionresult = new ContactResult(); | ||
537 | collisionresult.ConsumerID = ID; | ||
538 | collisionresult.Pos = new Vector3(curcontact.pos.X, curcontact.pos.Y, curcontact.pos.Z); | ||
539 | collisionresult.Depth = curcontact.depth; | ||
540 | collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y, | ||
541 | curcontact.normal.Z); | ||
542 | lock (m_contactResults) | ||
543 | { | ||
544 | m_contactResults.Add(collisionresult); | ||
545 | if (m_contactResults.Count >= CurrentMaxCount) | ||
546 | return; | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | else | ||
551 | { | ||
552 | // keep only closest contact | ||
553 | ContactResult collisionresult = new ContactResult(); | ||
554 | collisionresult.ConsumerID = ID; | ||
555 | collisionresult.Depth = float.MaxValue; | ||
556 | |||
557 | for (int i = 0; i < count; i++) | ||
558 | { | ||
559 | if (!GetCurContactGeom(i, ref curcontact)) | ||
560 | break; | ||
561 | |||
562 | if (curcontact.depth < collisionresult.Depth) | ||
410 | { | 563 | { |
411 | ContactResult collisionresult = new ContactResult(); | ||
412 | |||
413 | collisionresult.ConsumerID = ((OdePrim)p1).m_localID; | ||
414 | collisionresult.Pos = new Vector3(curcontact.pos.X, curcontact.pos.Y, curcontact.pos.Z); | 564 | collisionresult.Pos = new Vector3(curcontact.pos.X, curcontact.pos.Y, curcontact.pos.Z); |
415 | collisionresult.Depth = curcontact.depth; | 565 | collisionresult.Depth = curcontact.depth; |
416 | collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y, | 566 | collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y, |
417 | curcontact.normal.Z); | 567 | curcontact.normal.Z); |
418 | lock (m_contactResults) | ||
419 | m_contactResults.Add(collisionresult); | ||
420 | } | 568 | } |
421 | } | 569 | } |
570 | |||
571 | if (collisionresult.Depth != float.MaxValue) | ||
572 | { | ||
573 | lock (m_contactResults) | ||
574 | m_contactResults.Add(collisionresult); | ||
575 | } | ||
422 | } | 576 | } |
423 | } | 577 | } |
424 | 578 | ||
@@ -428,6 +582,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
428 | internal void Dispose() | 582 | internal void Dispose() |
429 | { | 583 | { |
430 | m_scene = null; | 584 | m_scene = null; |
585 | if (ray != IntPtr.Zero) | ||
586 | { | ||
587 | d.GeomDestroy(ray); | ||
588 | ray = IntPtr.Zero; | ||
589 | } | ||
431 | } | 590 | } |
432 | } | 591 | } |
433 | 592 | ||
@@ -439,5 +598,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
439 | public int Count; | 598 | public int Count; |
440 | public float length; | 599 | public float length; |
441 | public object callbackMethod; | 600 | public object callbackMethod; |
601 | public RayFilterFlags filter; | ||
442 | } | 602 | } |
443 | } \ No newline at end of file | 603 | } \ No newline at end of file |