aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs')
-rw-r--r--OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs689
1 files changed, 689 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs b/OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs
new file mode 100644
index 0000000..f671722
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs
@@ -0,0 +1,689 @@
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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using OpenSim.Framework;
34using OpenSim.Region.PhysicsModules.SharedBase;
35using OdeAPI;
36using log4net;
37using OpenMetaverse;
38
39namespace OpenSim.Region.PhysicsModule.ubOde
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 IntPtr Sphere;
60 IntPtr Box;
61 IntPtr Plane;
62
63 private int CollisionContactGeomsPerTest = 25;
64 private const int DefaultMaxCount = 25;
65 private const int MaxTimePerCallMS = 30;
66
67 /// <summary>
68 /// ODE near callback delegate
69 /// </summary>
70 private d.NearCallback nearCallback;
71 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
72 private List<ContactResult> m_contactResults = new List<ContactResult>();
73 private RayFilterFlags CurrentRayFilter;
74 private int CurrentMaxCount;
75
76 public ODERayCastRequestManager(ODEScene pScene)
77 {
78 m_scene = pScene;
79 nearCallback = near;
80 ray = d.CreateRay(IntPtr.Zero, 1.0f);
81 d.GeomSetCategoryBits(ray, 0);
82 Box = d.CreateBox(IntPtr.Zero, 1.0f, 1.0f, 1.0f);
83 d.GeomSetCategoryBits(Box, 0);
84 Sphere = d.CreateSphere(IntPtr.Zero,1.0f);
85 d.GeomSetCategoryBits(Sphere, 0);
86 Plane = d.CreatePlane(IntPtr.Zero, 0f,0f,1f,1f);
87 d.GeomSetCategoryBits(Sphere, 0);
88 }
89
90 public void QueueRequest(ODERayRequest req)
91 {
92 if (req.Count == 0)
93 req.Count = DefaultMaxCount;
94
95 m_PendingRequests.Enqueue(req);
96 }
97
98 /// <summary>
99 /// Process all queued raycast requests
100 /// </summary>
101 /// <returns>Time in MS the raycasts took to process.</returns>
102 public int ProcessQueuedRequests()
103 {
104
105 if (m_PendingRequests.Count <= 0)
106 return 0;
107
108 if (m_scene.ContactgeomsArray == IntPtr.Zero || ray == IntPtr.Zero)
109 // oops something got wrong or scene isn't ready still
110 {
111 m_PendingRequests.Clear();
112 return 0;
113 }
114
115 int time = Util.EnvironmentTickCount();
116
117 ODERayRequest req;
118 int closestHit;
119 int backfacecull;
120 CollisionCategories catflags;
121
122 while (m_PendingRequests.Dequeue(out req))
123 {
124 if (req.callbackMethod != null)
125 {
126 IntPtr geom = IntPtr.Zero;
127 if (req.actor != null)
128 {
129 if (m_scene.haveActor(req.actor))
130 {
131 if (req.actor is OdePrim)
132 geom = ((OdePrim)req.actor).prim_geom;
133 else if (req.actor is OdeCharacter)
134 geom = ((OdePrim)req.actor).prim_geom;
135 }
136 if (geom == IntPtr.Zero)
137 {
138 NoContacts(req);
139 continue;
140 }
141 }
142
143 CurrentRayFilter = req.filter;
144 CurrentMaxCount = req.Count;
145
146 CollisionContactGeomsPerTest = req.Count & 0xffff;
147
148 closestHit = ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0 ? 0 : 1);
149 backfacecull = ((CurrentRayFilter & RayFilterFlags.BackFaceCull) == 0 ? 0 : 1);
150
151 if (req.callbackMethod is ProbeBoxCallback)
152 {
153 if (CollisionContactGeomsPerTest > 80)
154 CollisionContactGeomsPerTest = 80;
155 d.GeomBoxSetLengths(Box, req.Normal.X, req.Normal.Y, req.Normal.Z);
156 d.GeomSetPosition(Box, req.Origin.X, req.Origin.Y, req.Origin.Z);
157 d.Quaternion qtmp;
158 qtmp.X = req.orientation.X;
159 qtmp.Y = req.orientation.Y;
160 qtmp.Z = req.orientation.Z;
161 qtmp.W = req.orientation.W;
162 d.GeomSetQuaternion(Box, ref qtmp);
163 }
164 else if (req.callbackMethod is ProbeSphereCallback)
165 {
166 if (CollisionContactGeomsPerTest > 80)
167 CollisionContactGeomsPerTest = 80;
168
169 d.GeomSphereSetRadius(Sphere, req.length);
170 d.GeomSetPosition(Sphere, req.Origin.X, req.Origin.Y, req.Origin.Z);
171 }
172 else if (req.callbackMethod is ProbePlaneCallback)
173 {
174 if (CollisionContactGeomsPerTest > 80)
175 CollisionContactGeomsPerTest = 80;
176
177 d.GeomPlaneSetParams(Plane, req.Normal.X, req.Normal.Y, req.Normal.Z, req.length);
178 }
179
180 else
181 {
182 if (CollisionContactGeomsPerTest > 25)
183 CollisionContactGeomsPerTest = 25;
184
185 d.GeomRaySetLength(ray, req.length);
186 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
187 d.GeomRaySetParams(ray, 0, backfacecull);
188
189 if (req.callbackMethod is RaycastCallback)
190 {
191 // if we only want one get only one per Collision pair saving memory
192 CurrentRayFilter |= RayFilterFlags.ClosestHit;
193 d.GeomRaySetClosestHit(ray, 1);
194 }
195 else
196 d.GeomRaySetClosestHit(ray, closestHit);
197 }
198
199 if ((CurrentRayFilter & RayFilterFlags.ContactsUnImportant) != 0)
200 unchecked
201 {
202 CollisionContactGeomsPerTest |= (int)d.CONTACTS_UNIMPORTANT;
203 }
204
205 if (geom == IntPtr.Zero)
206 {
207 // translate ray filter to Collision flags
208 catflags = 0;
209 if ((CurrentRayFilter & RayFilterFlags.volumedtc) != 0)
210 catflags |= CollisionCategories.VolumeDtc;
211 if ((CurrentRayFilter & RayFilterFlags.phantom) != 0)
212 catflags |= CollisionCategories.Phantom;
213 if ((CurrentRayFilter & RayFilterFlags.agent) != 0)
214 catflags |= CollisionCategories.Character;
215 if ((CurrentRayFilter & RayFilterFlags.PrimsNonPhantom) != 0)
216 catflags |= CollisionCategories.Geom;
217 if ((CurrentRayFilter & RayFilterFlags.land) != 0)
218 catflags |= CollisionCategories.Land;
219 if ((CurrentRayFilter & RayFilterFlags.water) != 0)
220 catflags |= CollisionCategories.Water;
221
222 if (catflags != 0)
223 {
224 if (req.callbackMethod is ProbeBoxCallback)
225 {
226 catflags |= CollisionCategories.Space;
227 d.GeomSetCollideBits(Box, (uint)catflags);
228 d.GeomSetCategoryBits(Box, (uint)catflags);
229 doProbe(req, Box);
230 }
231 else if (req.callbackMethod is ProbeSphereCallback)
232 {
233 catflags |= CollisionCategories.Space;
234 d.GeomSetCollideBits(Sphere, (uint)catflags);
235 d.GeomSetCategoryBits(Sphere, (uint)catflags);
236 doProbe(req, Sphere);
237 }
238 else if (req.callbackMethod is ProbePlaneCallback)
239 {
240 catflags |= CollisionCategories.Space;
241 d.GeomSetCollideBits(Plane, (uint)catflags);
242 d.GeomSetCategoryBits(Plane, (uint)catflags);
243 doPlane(req,IntPtr.Zero);
244 }
245 else
246 {
247 d.GeomSetCollideBits(ray, (uint)catflags);
248 doSpaceRay(req);
249 }
250 }
251 }
252 else
253 {
254 // if we select a geom don't use filters
255
256 if (req.callbackMethod is ProbePlaneCallback)
257 {
258 d.GeomSetCollideBits(Plane, (uint)CollisionCategories.All);
259 doPlane(req,geom);
260 }
261 else
262 {
263 d.GeomSetCollideBits(ray, (uint)CollisionCategories.All);
264 doGeomRay(req,geom);
265 }
266 }
267 }
268
269 if (Util.EnvironmentTickCountSubtract(time) > MaxTimePerCallMS)
270 break;
271 }
272
273 lock (m_contactResults)
274 m_contactResults.Clear();
275
276 return Util.EnvironmentTickCountSubtract(time);
277 }
278 /// <summary>
279 /// Method that actually initiates the raycast with spaces
280 /// </summary>
281 /// <param name="req"></param>
282 ///
283
284 private void NoContacts(ODERayRequest req)
285 {
286 if (req.callbackMethod is RaycastCallback)
287 {
288 ((RaycastCallback)req.callbackMethod)(false, Vector3.Zero, 0, 0, Vector3.Zero);
289 return;
290 }
291 List<ContactResult> cresult = new List<ContactResult>();
292
293 if (req.callbackMethod is RayCallback)
294 ((RayCallback)req.callbackMethod)(cresult);
295 else if (req.callbackMethod is ProbeBoxCallback)
296 ((ProbeBoxCallback)req.callbackMethod)(cresult);
297 else if (req.callbackMethod is ProbeSphereCallback)
298 ((ProbeSphereCallback)req.callbackMethod)(cresult);
299 }
300
301 private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhantom;
302// private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton;
303 private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhantom;
304
305 private void doSpaceRay(ODERayRequest req)
306 {
307 // Collide tests
308 if ((CurrentRayFilter & FilterActiveSpace) != 0)
309 {
310 d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
311 d.SpaceCollide2(ray, m_scene.CharsSpace, IntPtr.Zero, nearCallback);
312 }
313 if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
314 d.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
315 if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
316 {
317 // current ode land to ray collisions is very bad
318 // so for now limit its range badly
319 if (req.length > 60.0f)
320 {
321 Vector3 t = req.Normal * req.length;
322 float tmp = t.X * t.X + t.Y * t.Y;
323 if(tmp > 2500)
324 {
325 float tmp2 = req.length * req.length - tmp + 2500;
326 tmp2 = (float)Math.Sqrt(tmp2);
327 d.GeomRaySetLength(ray, tmp2);
328 }
329
330 }
331 d.SpaceCollide2(ray, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
332 }
333
334 if (req.callbackMethod is RaycastCallback)
335 {
336 // Define default results
337 bool hitYN = false;
338 uint hitConsumerID = 0;
339 float distance = float.MaxValue;
340 Vector3 closestcontact = Vector3.Zero;
341 Vector3 snormal = Vector3.Zero;
342
343 // Find closest contact and object.
344 lock (m_contactResults)
345 {
346 foreach (ContactResult cResult in m_contactResults)
347 {
348 if(cResult.Depth < distance)
349 {
350 closestcontact = cResult.Pos;
351 hitConsumerID = cResult.ConsumerID;
352 distance = cResult.Depth;
353 snormal = cResult.Normal;
354 }
355 }
356 m_contactResults.Clear();
357 }
358
359 if (distance > 0 && distance < float.MaxValue)
360 hitYN = true;
361 ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
362 }
363 else
364 {
365 List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
366 lock (m_PendingRequests)
367 {
368 cresult.AddRange(m_contactResults);
369 m_contactResults.Clear();
370 }
371 ((RayCallback)req.callbackMethod)(cresult);
372 }
373 }
374
375 private void doProbe(ODERayRequest req, IntPtr probe)
376 {
377 // Collide tests
378 if ((CurrentRayFilter & FilterActiveSpace) != 0)
379 {
380 d.SpaceCollide2(probe, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
381 d.SpaceCollide2(probe, m_scene.CharsSpace, IntPtr.Zero, nearCallback);
382 }
383 if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
384 d.SpaceCollide2(probe, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
385 if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
386 d.SpaceCollide2(probe, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
387
388 List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
389 lock (m_PendingRequests)
390 {
391 cresult.AddRange(m_contactResults);
392 m_contactResults.Clear();
393 }
394 if (req.callbackMethod is ProbeBoxCallback)
395 ((ProbeBoxCallback)req.callbackMethod)(cresult);
396 else if (req.callbackMethod is ProbeSphereCallback)
397 ((ProbeSphereCallback)req.callbackMethod)(cresult);
398 }
399
400 private void doPlane(ODERayRequest req,IntPtr geom)
401 {
402 // Collide tests
403 if (geom == IntPtr.Zero)
404 {
405 if ((CurrentRayFilter & FilterActiveSpace) != 0)
406 {
407 d.SpaceCollide2(Plane, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
408 d.SpaceCollide2(Plane, m_scene.CharsSpace, IntPtr.Zero, nearCallback);
409 }
410 if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
411 d.SpaceCollide2(Plane, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
412 if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
413 d.SpaceCollide2(Plane, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
414 }
415 else
416 {
417 d.SpaceCollide2(Plane, geom, IntPtr.Zero, nearCallback);
418 }
419
420 List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
421 lock (m_PendingRequests)
422 {
423 cresult.AddRange(m_contactResults);
424 m_contactResults.Clear();
425 }
426
427 ((ProbePlaneCallback)req.callbackMethod)(cresult);
428 }
429
430 /// <summary>
431 /// Method that actually initiates the raycast with a geom
432 /// </summary>
433 /// <param name="req"></param>
434 private void doGeomRay(ODERayRequest req, IntPtr geom)
435 {
436 // Collide test
437 d.SpaceCollide2(ray, geom, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test
438
439 if (req.callbackMethod is RaycastCallback)
440 {
441 // Define default results
442 bool hitYN = false;
443 uint hitConsumerID = 0;
444 float distance = float.MaxValue;
445 Vector3 closestcontact = Vector3.Zero;
446 Vector3 snormal = Vector3.Zero;
447
448 // Find closest contact and object.
449 lock (m_contactResults)
450 {
451 foreach (ContactResult cResult in m_contactResults)
452 {
453 if(cResult.Depth < distance )
454 {
455 closestcontact = cResult.Pos;
456 hitConsumerID = cResult.ConsumerID;
457 distance = cResult.Depth;
458 snormal = cResult.Normal;
459 }
460 }
461 m_contactResults.Clear();
462 }
463
464 if (distance > 0 && distance < float.MaxValue)
465 hitYN = true;
466
467 ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
468 }
469 else
470 {
471 List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
472 lock (m_PendingRequests)
473 {
474 cresult.AddRange(m_contactResults);
475 m_contactResults.Clear();
476 }
477 ((RayCallback)req.callbackMethod)(cresult);
478 }
479 }
480
481 private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom)
482 {
483 IntPtr ContactgeomsArray = m_scene.ContactgeomsArray;
484 if (ContactgeomsArray == IntPtr.Zero || index >= CollisionContactGeomsPerTest)
485 return false;
486
487 IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf));
488 newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom));
489 return true;
490 }
491
492 // This is the standard Near. g1 is the ray
493 private void near(IntPtr space, IntPtr g1, IntPtr g2)
494 {
495 if (g2 == IntPtr.Zero || g1 == g2)
496 return;
497
498 if (m_contactResults.Count >= CurrentMaxCount)
499 return;
500
501 if (d.GeomIsSpace(g2))
502 {
503 try
504 {
505 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
506 }
507 catch (Exception e)
508 {
509 m_log.WarnFormat("[PHYSICS Ray]: Unable to Space collide test an object: {0}", e.Message);
510 }
511 return;
512 }
513
514 int count = 0;
515 try
516 {
517 count = d.CollidePtr(g1, g2, CollisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
518 }
519 catch (Exception e)
520 {
521 m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
522 return;
523 }
524
525 if (count == 0)
526 return;
527/*
528 uint cat1 = d.GeomGetCategoryBits(g1);
529 uint cat2 = d.GeomGetCategoryBits(g2);
530 uint col1 = d.GeomGetCollideBits(g1);
531 uint col2 = d.GeomGetCollideBits(g2);
532*/
533
534 uint ID = 0;
535 PhysicsActor p2 = null;
536
537 m_scene.actor_name_map.TryGetValue(g2, out p2);
538
539 if (p2 == null)
540 return;
541
542 switch (p2.PhysicsActorType)
543 {
544 case (int)ActorTypes.Prim:
545
546 RayFilterFlags thisFlags;
547
548 if (p2.IsPhysical)
549 thisFlags = RayFilterFlags.physical;
550 else
551 thisFlags = RayFilterFlags.nonphysical;
552
553 if (p2.Phantom)
554 thisFlags |= RayFilterFlags.phantom;
555
556 if (p2.IsVolumeDtc)
557 thisFlags |= RayFilterFlags.volumedtc;
558
559 if ((thisFlags & CurrentRayFilter) == 0)
560 return;
561
562 ID = ((OdePrim)p2).LocalID;
563 break;
564
565 case (int)ActorTypes.Agent:
566
567 if ((CurrentRayFilter & RayFilterFlags.agent) == 0)
568 return;
569 else
570 ID = ((OdeCharacter)p2).LocalID;
571 break;
572
573 case (int)ActorTypes.Ground:
574
575 if ((CurrentRayFilter & RayFilterFlags.land) == 0)
576 return;
577 break;
578
579 case (int)ActorTypes.Water:
580
581 if ((CurrentRayFilter & RayFilterFlags.water) == 0)
582 return;
583 break;
584
585 default:
586 break;
587 }
588
589 d.ContactGeom curcontact = new d.ContactGeom();
590
591 // closestHit for now only works for meshs, so must do it for others
592 if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
593 {
594 // Loop all contacts, build results.
595 for (int i = 0; i < count; i++)
596 {
597 if (!GetCurContactGeom(i, ref curcontact))
598 break;
599
600 ContactResult collisionresult = new ContactResult();
601 collisionresult.ConsumerID = ID;
602 collisionresult.Pos.X = curcontact.pos.X;
603 collisionresult.Pos.Y = curcontact.pos.Y;
604 collisionresult.Pos.Z = curcontact.pos.Z;
605 collisionresult.Depth = curcontact.depth;
606 collisionresult.Normal.X = curcontact.normal.X;
607 collisionresult.Normal.Y = curcontact.normal.Y;
608 collisionresult.Normal.Z = curcontact.normal.Z;
609 lock (m_contactResults)
610 {
611 m_contactResults.Add(collisionresult);
612 if (m_contactResults.Count >= CurrentMaxCount)
613 return;
614 }
615 }
616 }
617 else
618 {
619 // keep only closest contact
620 ContactResult collisionresult = new ContactResult();
621 collisionresult.ConsumerID = ID;
622 collisionresult.Depth = float.MaxValue;
623
624 for (int i = 0; i < count; i++)
625 {
626 if (!GetCurContactGeom(i, ref curcontact))
627 break;
628
629 if (curcontact.depth < collisionresult.Depth)
630 {
631 collisionresult.Pos.X = curcontact.pos.X;
632 collisionresult.Pos.Y = curcontact.pos.Y;
633 collisionresult.Pos.Z = curcontact.pos.Z;
634 collisionresult.Depth = curcontact.depth;
635 collisionresult.Normal.X = curcontact.normal.X;
636 collisionresult.Normal.Y = curcontact.normal.Y;
637 collisionresult.Normal.Z = curcontact.normal.Z;
638 }
639 }
640
641 if (collisionresult.Depth != float.MaxValue)
642 {
643 lock (m_contactResults)
644 m_contactResults.Add(collisionresult);
645 }
646 }
647 }
648
649 /// <summary>
650 /// Dereference the creator scene so that it can be garbage collected if needed.
651 /// </summary>
652 internal void Dispose()
653 {
654 m_scene = null;
655 if (ray != IntPtr.Zero)
656 {
657 d.GeomDestroy(ray);
658 ray = IntPtr.Zero;
659 }
660 if (Box != IntPtr.Zero)
661 {
662 d.GeomDestroy(Box);
663 Box = IntPtr.Zero;
664 }
665 if (Sphere != IntPtr.Zero)
666 {
667 d.GeomDestroy(Sphere);
668 Sphere = IntPtr.Zero;
669 }
670 if (Plane != IntPtr.Zero)
671 {
672 d.GeomDestroy(Plane);
673 Plane = IntPtr.Zero;
674 }
675 }
676 }
677
678 public struct ODERayRequest
679 {
680 public PhysicsActor actor;
681 public Vector3 Origin;
682 public Vector3 Normal;
683 public int Count;
684 public float length;
685 public object callbackMethod;
686 public RayFilterFlags filter;
687 public Quaternion orientation;
688 }
689}