diff options
author | Melanie | 2012-04-17 01:50:49 +0100 |
---|---|---|
committer | Melanie | 2012-04-17 01:50:49 +0100 |
commit | ab1a3688e24db08071f74c9804d552d5763bbeb2 (patch) | |
tree | 030bafc8ce646fbf80bd20a1e7647618222e7fc2 /OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs | |
parent | Merge branch 'master' into careminster (diff) | |
parent | Merge branch 'ubitwork' (diff) | |
download | opensim-SC-ab1a3688e24db08071f74c9804d552d5763bbeb2.zip opensim-SC-ab1a3688e24db08071f74c9804d552d5763bbeb2.tar.gz opensim-SC-ab1a3688e24db08071f74c9804d552d5763bbeb2.tar.bz2 opensim-SC-ab1a3688e24db08071f74c9804d552d5763bbeb2.tar.xz |
Merge branch 'master' of ssh://melanie@3dhosting.de/var/git/careminster into careminster
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..5122ebf 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.AllPrims; | ||
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.AllPrims; | ||
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.AllPrims; | ||
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.AllPrims; | ||
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.AllPrims; | ||
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.AllPrims; | ||
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.AllPrims; | ||
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.AllPrims; | ||
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 |