diff options
Diffstat (limited to 'OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs')
-rw-r--r-- | OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs | 638 |
1 files changed, 638 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs new file mode 100644 index 0000000..799a324 --- /dev/null +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs | |||
@@ -0,0 +1,638 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Runtime.InteropServices; | ||
32 | using System.Text; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | using OdeAPI; | ||
36 | using log4net; | ||
37 | using OpenMetaverse; | ||
38 | |||
39 | namespace OpenSim.Region.Physics.OdePlugin | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// Processes raycast requests as ODE is in a state to be able to do them. | ||
43 | /// This ensures that it's thread safe and there will be no conflicts. | ||
44 | /// Requests get returned by a different thread then they were requested by. | ||
45 | /// </summary> | ||
46 | public class ODERayCastRequestManager | ||
47 | { | ||
48 | /// <summary> | ||
49 | /// Pending ray requests | ||
50 | /// </summary> | ||
51 | protected OpenSim.Framework.LocklessQueue<ODERayRequest> m_PendingRequests = new OpenSim.Framework.LocklessQueue<ODERayRequest>(); | ||
52 | |||
53 | /// <summary> | ||
54 | /// Scene that created this object. | ||
55 | /// </summary> | ||
56 | private OdeScene m_scene; | ||
57 | |||
58 | IntPtr ray; // the ray. we only need one for our lifetime | ||
59 | |||
60 | private const int ColisionContactGeomsPerTest = 5; | ||
61 | private const int DefaultMaxCount = 25; | ||
62 | private const int MaxTimePerCallMS = 30; | ||
63 | |||
64 | /// <summary> | ||
65 | /// ODE near callback delegate | ||
66 | /// </summary> | ||
67 | private d.NearCallback nearCallback; | ||
68 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
69 | private List<ContactResult> m_contactResults = new List<ContactResult>(); | ||
70 | private RayFilterFlags CurrentRayFilter; | ||
71 | private int CurrentMaxCount; | ||
72 | |||
73 | public ODERayCastRequestManager(OdeScene pScene) | ||
74 | { | ||
75 | m_scene = pScene; | ||
76 | nearCallback = near; | ||
77 | ray = d.CreateRay(IntPtr.Zero, 1.0f); | ||
78 | d.GeomSetCategoryBits(ray,0); | ||
79 | } | ||
80 | |||
81 | /// <summary> | ||
82 | /// Queues request for a raycast to all world | ||
83 | /// </summary> | ||
84 | /// <param name="position">Origin of Ray</param> | ||
85 | /// <param name="direction">Ray direction</param> | ||
86 | /// <param name="length">Ray length</param> | ||
87 | /// <param name="retMethod">Return method to send the results</param> | ||
88 | public void QueueRequest(Vector3 position, Vector3 direction, float length, RayCallback retMethod) | ||
89 | { | ||
90 | ODERayRequest req = new ODERayRequest(); | ||
91 | req.geom = IntPtr.Zero; | ||
92 | req.callbackMethod = retMethod; | ||
93 | req.Count = DefaultMaxCount; | ||
94 | req.length = length; | ||
95 | req.Normal = direction; | ||
96 | req.Origin = position; | ||
97 | req.filter = RayFilterFlags.AllPrims; | ||
98 | |||
99 | m_PendingRequests.Enqueue(req); | ||
100 | } | ||
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> | ||
109 | public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, RayCallback retMethod) | ||
110 | { | ||
111 | ODERayRequest req = new ODERayRequest(); | ||
112 | req.geom = geom; | ||
113 | req.callbackMethod = retMethod; | ||
114 | req.length = length; | ||
115 | req.Normal = direction; | ||
116 | req.Origin = position; | ||
117 | req.Count = DefaultMaxCount; | ||
118 | req.filter = RayFilterFlags.AllPrims; | ||
119 | |||
120 | m_PendingRequests.Enqueue(req); | ||
121 | } | ||
122 | |||
123 | public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) | ||
124 | { | ||
125 | ODERayRequest req = new ODERayRequest(); | ||
126 | req.geom = IntPtr.Zero; | ||
127 | req.callbackMethod = retMethod; | ||
128 | req.Count = DefaultMaxCount; | ||
129 | req.length = length; | ||
130 | req.Normal = direction; | ||
131 | req.Origin = position; | ||
132 | req.filter = RayFilterFlags.AllPrims | RayFilterFlags.land; | ||
133 | |||
134 | m_PendingRequests.Enqueue(req); | ||
135 | } | ||
136 | |||
137 | public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) | ||
138 | { | ||
139 | ODERayRequest req = new ODERayRequest(); | ||
140 | req.geom = geom; | ||
141 | req.callbackMethod = retMethod; | ||
142 | req.length = length; | ||
143 | req.Normal = direction; | ||
144 | req.Origin = position; | ||
145 | req.Count = DefaultMaxCount; | ||
146 | req.filter = RayFilterFlags.AllPrims; | ||
147 | |||
148 | m_PendingRequests.Enqueue(req); | ||
149 | } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Queues a raycast | ||
153 | /// </summary> | ||
154 | /// <param name="position">Origin of Ray</param> | ||
155 | /// <param name="direction">Ray normal</param> | ||
156 | /// <param name="length">Ray length</param> | ||
157 | /// <param name="count"></param> | ||
158 | /// <param name="retMethod">Return method to send the results</param> | ||
159 | public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod) | ||
160 | { | ||
161 | ODERayRequest req = new ODERayRequest(); | ||
162 | req.geom = IntPtr.Zero; | ||
163 | req.callbackMethod = retMethod; | ||
164 | req.length = length; | ||
165 | req.Normal = direction; | ||
166 | req.Origin = position; | ||
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; | ||
184 | |||
185 | m_PendingRequests.Enqueue(req); | ||
186 | } | ||
187 | |||
188 | public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod) | ||
189 | { | ||
190 | ODERayRequest req = new ODERayRequest(); | ||
191 | req.geom = geom; | ||
192 | req.callbackMethod = retMethod; | ||
193 | req.length = length; | ||
194 | req.Normal = direction; | ||
195 | req.Origin = position; | ||
196 | req.Count = count; | ||
197 | req.filter = RayFilterFlags.AllPrims; | ||
198 | |||
199 | m_PendingRequests.Enqueue(req); | ||
200 | } | ||
201 | |||
202 | public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RaycastCallback retMethod) | ||
203 | { | ||
204 | ODERayRequest req = new ODERayRequest(); | ||
205 | req.geom = IntPtr.Zero; | ||
206 | req.callbackMethod = retMethod; | ||
207 | req.length = length; | ||
208 | req.Normal = direction; | ||
209 | req.Origin = position; | ||
210 | req.Count = count; | ||
211 | req.filter = RayFilterFlags.AllPrims; | ||
212 | |||
213 | m_PendingRequests.Enqueue(req); | ||
214 | } | ||
215 | |||
216 | public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, int count, RaycastCallback retMethod) | ||
217 | { | ||
218 | ODERayRequest req = new ODERayRequest(); | ||
219 | req.geom = geom; | ||
220 | req.callbackMethod = retMethod; | ||
221 | req.length = length; | ||
222 | req.Normal = direction; | ||
223 | req.Origin = position; | ||
224 | req.Count = count; | ||
225 | req.filter = RayFilterFlags.AllPrims; | ||
226 | |||
227 | m_PendingRequests.Enqueue(req); | ||
228 | } | ||
229 | |||
230 | /// <summary> | ||
231 | /// Process all queued raycast requests | ||
232 | /// </summary> | ||
233 | /// <returns>Time in MS the raycasts took to process.</returns> | ||
234 | public int ProcessQueuedRequests() | ||
235 | { | ||
236 | |||
237 | if (m_PendingRequests.Count <= 0) | ||
238 | return 0; | ||
239 | |||
240 | if (m_scene.ContactgeomsArray == IntPtr.Zero || ray == IntPtr.Zero) | ||
241 | // oops something got wrong or scene isn't ready still | ||
242 | { | ||
243 | m_PendingRequests.Clear(); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | int time = Util.EnvironmentTickCount(); | ||
248 | |||
249 | ODERayRequest req; | ||
250 | int closestHit; | ||
251 | int backfacecull; | ||
252 | CollisionCategories catflags; | ||
253 | |||
254 | while (m_PendingRequests.Dequeue(out req)) | ||
255 | { | ||
256 | if (req.callbackMethod != null) | ||
257 | { | ||
258 | CurrentRayFilter = req.filter; | ||
259 | CurrentMaxCount = req.Count; | ||
260 | |||
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 | { | ||
292 | d.GeomSetCollideBits(ray, (uint)catflags); | ||
293 | doSpaceRay(req); | ||
294 | } | ||
295 | } | ||
296 | else | ||
297 | { | ||
298 | // if we select a geom don't use filters | ||
299 | d.GeomSetCollideBits(ray, (uint)CollisionCategories.All); | ||
300 | doGeomRay(req); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | if (Util.EnvironmentTickCountSubtract(time) > MaxTimePerCallMS) | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | lock (m_contactResults) | ||
309 | m_contactResults.Clear(); | ||
310 | |||
311 | return Util.EnvironmentTickCountSubtract(time); | ||
312 | } | ||
313 | /// <summary> | ||
314 | /// Method that actually initiates the raycast with spaces | ||
315 | /// </summary> | ||
316 | /// <param name="req"></param> | ||
317 | /// | ||
318 | |||
319 | private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhanton; | ||
320 | // private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; | ||
321 | private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; | ||
322 | |||
323 | private void doSpaceRay(ODERayRequest req) | ||
324 | { | ||
325 | // Collide tests | ||
326 | if ((CurrentRayFilter & FilterActiveSpace) != 0) | ||
327 | d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback); | ||
328 | if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount)) | ||
329 | d.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback); | ||
330 | if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount)) | ||
331 | { | ||
332 | // current ode land to ray collisions is very bad | ||
333 | // so for now limit its range badly | ||
334 | |||
335 | if (req.length > 30.0f) | ||
336 | d.GeomRaySetLength(ray, 30.0f); | ||
337 | |||
338 | d.SpaceCollide2(ray, m_scene.GroundSpace, IntPtr.Zero, nearCallback); | ||
339 | } | ||
340 | |||
341 | if (req.callbackMethod is RaycastCallback) | ||
342 | { | ||
343 | // Define default results | ||
344 | bool hitYN = false; | ||
345 | uint hitConsumerID = 0; | ||
346 | float distance = float.MaxValue; | ||
347 | Vector3 closestcontact = Vector3.Zero; | ||
348 | Vector3 snormal = Vector3.Zero; | ||
349 | |||
350 | // Find closest contact and object. | ||
351 | lock (m_contactResults) | ||
352 | { | ||
353 | foreach (ContactResult cResult in m_contactResults) | ||
354 | { | ||
355 | if(cResult.Depth < distance) | ||
356 | { | ||
357 | closestcontact = cResult.Pos; | ||
358 | hitConsumerID = cResult.ConsumerID; | ||
359 | distance = cResult.Depth; | ||
360 | snormal = cResult.Normal; | ||
361 | } | ||
362 | } | ||
363 | m_contactResults.Clear(); | ||
364 | } | ||
365 | |||
366 | if (distance > 0 && distance < float.MaxValue) | ||
367 | hitYN = true; | ||
368 | ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal); | ||
369 | } | ||
370 | else | ||
371 | { | ||
372 | List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count); | ||
373 | lock (m_PendingRequests) | ||
374 | { | ||
375 | cresult.AddRange(m_contactResults); | ||
376 | m_contactResults.Clear(); | ||
377 | } | ||
378 | ((RayCallback)req.callbackMethod)(cresult); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | /// <summary> | ||
383 | /// Method that actually initiates the raycast with a geom | ||
384 | /// </summary> | ||
385 | /// <param name="req"></param> | ||
386 | private void doGeomRay(ODERayRequest req) | ||
387 | { | ||
388 | // Collide test | ||
389 | d.SpaceCollide2(ray, req.geom, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test | ||
390 | |||
391 | if (req.callbackMethod is RaycastCallback) | ||
392 | { | ||
393 | // Define default results | ||
394 | bool hitYN = false; | ||
395 | uint hitConsumerID = 0; | ||
396 | float distance = float.MaxValue; | ||
397 | Vector3 closestcontact = Vector3.Zero; | ||
398 | Vector3 snormal = Vector3.Zero; | ||
399 | |||
400 | // Find closest contact and object. | ||
401 | lock (m_contactResults) | ||
402 | { | ||
403 | foreach (ContactResult cResult in m_contactResults) | ||
404 | { | ||
405 | if(cResult.Depth < distance ) | ||
406 | { | ||
407 | closestcontact = cResult.Pos; | ||
408 | hitConsumerID = cResult.ConsumerID; | ||
409 | distance = cResult.Depth; | ||
410 | snormal = cResult.Normal; | ||
411 | } | ||
412 | } | ||
413 | m_contactResults.Clear(); | ||
414 | } | ||
415 | |||
416 | if (distance > 0 && distance < float.MaxValue) | ||
417 | hitYN = true; | ||
418 | |||
419 | ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal); | ||
420 | } | ||
421 | else | ||
422 | { | ||
423 | List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count); | ||
424 | lock (m_PendingRequests) | ||
425 | { | ||
426 | cresult.AddRange(m_contactResults); | ||
427 | m_contactResults.Clear(); | ||
428 | } | ||
429 | ((RayCallback)req.callbackMethod)(cresult); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom) | ||
434 | { | ||
435 | IntPtr ContactgeomsArray = m_scene.ContactgeomsArray; | ||
436 | if (ContactgeomsArray == IntPtr.Zero || index >= ColisionContactGeomsPerTest) | ||
437 | return false; | ||
438 | |||
439 | IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf)); | ||
440 | newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom)); | ||
441 | return true; | ||
442 | } | ||
443 | |||
444 | // This is the standard Near. g1 is the ray | ||
445 | private void near(IntPtr space, IntPtr g1, IntPtr g2) | ||
446 | { | ||
447 | if (g2 == IntPtr.Zero || g1 == g2) | ||
448 | return; | ||
449 | |||
450 | if (m_contactResults.Count >= CurrentMaxCount) | ||
451 | return; | ||
452 | |||
453 | if (d.GeomIsSpace(g2)) | ||
454 | { | ||
455 | try | ||
456 | { | ||
457 | d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); | ||
458 | } | ||
459 | catch (Exception e) | ||
460 | { | ||
461 | m_log.WarnFormat("[PHYSICS Ray]: Unable to Space collide test an object: {0}", e.Message); | ||
462 | } | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | int count = 0; | ||
467 | try | ||
468 | { | ||
469 | count = d.CollidePtr(g1, g2, ColisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); | ||
470 | } | ||
471 | catch (Exception e) | ||
472 | { | ||
473 | m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message); | ||
474 | return; | ||
475 | } | ||
476 | |||
477 | if (count == 0) | ||
478 | return; | ||
479 | |||
480 | uint ID = 0; | ||
481 | PhysicsActor p2 = null; | ||
482 | |||
483 | m_scene.actor_name_map.TryGetValue(g2, out p2); | ||
484 | |||
485 | if (p2 == null) | ||
486 | { | ||
487 | /* | ||
488 | string name; | ||
489 | |||
490 | if (!m_scene.geom_name_map.TryGetValue(g2, out name)) | ||
491 | return; | ||
492 | |||
493 | if (name == "Terrain") | ||
494 | { | ||
495 | // land colision | ||
496 | if ((CurrentRayFilter & RayFilterFlags.land) == 0) | ||
497 | return; | ||
498 | } | ||
499 | else if (name == "Water") | ||
500 | { | ||
501 | if ((CurrentRayFilter & RayFilterFlags.water) == 0) | ||
502 | return; | ||
503 | } | ||
504 | else | ||
505 | return; | ||
506 | */ | ||
507 | return; | ||
508 | } | ||
509 | else | ||
510 | { | ||
511 | switch (p2.PhysicsActorType) | ||
512 | { | ||
513 | case (int)ActorTypes.Prim: | ||
514 | |||
515 | RayFilterFlags thisFlags; | ||
516 | |||
517 | if (p2.IsPhysical) | ||
518 | thisFlags = RayFilterFlags.physical; | ||
519 | else | ||
520 | thisFlags = RayFilterFlags.nonphysical; | ||
521 | |||
522 | if (p2.Phantom) | ||
523 | thisFlags |= RayFilterFlags.phantom; | ||
524 | |||
525 | if (p2.IsVolumeDtc) | ||
526 | thisFlags |= RayFilterFlags.volumedtc; | ||
527 | |||
528 | if ((thisFlags & CurrentRayFilter) == 0) | ||
529 | return; | ||
530 | |||
531 | ID = ((OdePrim)p2).LocalID; | ||
532 | break; | ||
533 | |||
534 | case (int)ActorTypes.Agent: | ||
535 | |||
536 | if ((CurrentRayFilter & RayFilterFlags.agent) == 0) | ||
537 | return; | ||
538 | else | ||
539 | ID = ((OdeCharacter)p2).LocalID; | ||
540 | break; | ||
541 | |||
542 | case (int)ActorTypes.Ground: | ||
543 | |||
544 | if ((CurrentRayFilter & RayFilterFlags.land) == 0) | ||
545 | return; | ||
546 | break; | ||
547 | |||
548 | case (int)ActorTypes.Water: | ||
549 | |||
550 | if ((CurrentRayFilter & RayFilterFlags.water) == 0) | ||
551 | return; | ||
552 | break; | ||
553 | |||
554 | default: | ||
555 | return; | ||
556 | break; | ||
557 | } | ||
558 | } | ||
559 | |||
560 | d.ContactGeom curcontact = new d.ContactGeom(); | ||
561 | |||
562 | // closestHit for now only works for meshs, so must do it for others | ||
563 | if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0) | ||
564 | { | ||
565 | // Loop all contacts, build results. | ||
566 | for (int i = 0; i < count; i++) | ||
567 | { | ||
568 | if (!GetCurContactGeom(i, ref curcontact)) | ||
569 | break; | ||
570 | |||
571 | ContactResult collisionresult = new ContactResult(); | ||
572 | collisionresult.ConsumerID = ID; | ||
573 | collisionresult.Pos = new Vector3(curcontact.pos.X, curcontact.pos.Y, curcontact.pos.Z); | ||
574 | collisionresult.Depth = curcontact.depth; | ||
575 | collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y, | ||
576 | curcontact.normal.Z); | ||
577 | lock (m_contactResults) | ||
578 | { | ||
579 | m_contactResults.Add(collisionresult); | ||
580 | if (m_contactResults.Count >= CurrentMaxCount) | ||
581 | return; | ||
582 | } | ||
583 | } | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | // keep only closest contact | ||
588 | ContactResult collisionresult = new ContactResult(); | ||
589 | collisionresult.ConsumerID = ID; | ||
590 | collisionresult.Depth = float.MaxValue; | ||
591 | |||
592 | for (int i = 0; i < count; i++) | ||
593 | { | ||
594 | if (!GetCurContactGeom(i, ref curcontact)) | ||
595 | break; | ||
596 | |||
597 | if (curcontact.depth < collisionresult.Depth) | ||
598 | { | ||
599 | collisionresult.Pos = new Vector3(curcontact.pos.X, curcontact.pos.Y, curcontact.pos.Z); | ||
600 | collisionresult.Depth = curcontact.depth; | ||
601 | collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y, | ||
602 | curcontact.normal.Z); | ||
603 | } | ||
604 | } | ||
605 | |||
606 | if (collisionresult.Depth != float.MaxValue) | ||
607 | { | ||
608 | lock (m_contactResults) | ||
609 | m_contactResults.Add(collisionresult); | ||
610 | } | ||
611 | } | ||
612 | } | ||
613 | |||
614 | /// <summary> | ||
615 | /// Dereference the creator scene so that it can be garbage collected if needed. | ||
616 | /// </summary> | ||
617 | internal void Dispose() | ||
618 | { | ||
619 | m_scene = null; | ||
620 | if (ray != IntPtr.Zero) | ||
621 | { | ||
622 | d.GeomDestroy(ray); | ||
623 | ray = IntPtr.Zero; | ||
624 | } | ||
625 | } | ||
626 | } | ||
627 | |||
628 | public struct ODERayRequest | ||
629 | { | ||
630 | public IntPtr geom; | ||
631 | public Vector3 Origin; | ||
632 | public Vector3 Normal; | ||
633 | public int Count; | ||
634 | public float length; | ||
635 | public object callbackMethod; | ||
636 | public RayFilterFlags filter; | ||
637 | } | ||
638 | } \ No newline at end of file | ||