OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ODERayCastRequestManager.cs
Go to the documentation of this file.
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.PhysicsModules.SharedBase;
35 using OdeAPI;
36 using log4net;
37 using OpenMetaverse;
38 
39 namespace OpenSim.Region.PhysicsModule.ubOde
40 {
47  {
51  protected OpenSim.Framework.LocklessQueue<ODERayRequest> m_PendingRequests = new OpenSim.Framework.LocklessQueue<ODERayRequest>();
52 
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 
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 
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 
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  }
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  d.GeomRaySetLength(ray, 60.0f);
321 
322  d.SpaceCollide2(ray, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
323  }
324 
325  if (req.callbackMethod is RaycastCallback)
326  {
327  // Define default results
328  bool hitYN = false;
329  uint hitConsumerID = 0;
330  float distance = float.MaxValue;
331  Vector3 closestcontact = Vector3.Zero;
332  Vector3 snormal = Vector3.Zero;
333 
334  // Find closest contact and object.
335  lock (m_contactResults)
336  {
337  foreach (ContactResult cResult in m_contactResults)
338  {
339  if(cResult.Depth < distance)
340  {
341  closestcontact = cResult.Pos;
342  hitConsumerID = cResult.ConsumerID;
343  distance = cResult.Depth;
344  snormal = cResult.Normal;
345  }
346  }
347  m_contactResults.Clear();
348  }
349 
350  if (distance > 0 && distance < float.MaxValue)
351  hitYN = true;
352  ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
353  }
354  else
355  {
356  List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
357  lock (m_PendingRequests)
358  {
359  cresult.AddRange(m_contactResults);
360  m_contactResults.Clear();
361  }
362  ((RayCallback)req.callbackMethod)(cresult);
363  }
364  }
365 
366  private void doProbe(ODERayRequest req, IntPtr probe)
367  {
368  // Collide tests
369  if ((CurrentRayFilter & FilterActiveSpace) != 0)
370  {
371  d.SpaceCollide2(probe, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
372  d.SpaceCollide2(probe, m_scene.CharsSpace, IntPtr.Zero, nearCallback);
373  }
374  if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
375  d.SpaceCollide2(probe, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
376  if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
377  d.SpaceCollide2(probe, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
378 
379  List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
380  lock (m_PendingRequests)
381  {
382  cresult.AddRange(m_contactResults);
383  m_contactResults.Clear();
384  }
385  if (req.callbackMethod is ProbeBoxCallback)
386  ((ProbeBoxCallback)req.callbackMethod)(cresult);
387  else if (req.callbackMethod is ProbeSphereCallback)
388  ((ProbeSphereCallback)req.callbackMethod)(cresult);
389  }
390 
391  private void doPlane(ODERayRequest req,IntPtr geom)
392  {
393  // Collide tests
394  if (geom == IntPtr.Zero)
395  {
396  if ((CurrentRayFilter & FilterActiveSpace) != 0)
397  {
398  d.SpaceCollide2(Plane, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
399  d.SpaceCollide2(Plane, m_scene.CharsSpace, IntPtr.Zero, nearCallback);
400  }
401  if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
402  d.SpaceCollide2(Plane, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
403  if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
404  d.SpaceCollide2(Plane, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
405  }
406  else
407  {
408  d.SpaceCollide2(Plane, geom, IntPtr.Zero, nearCallback);
409  }
410 
411  List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
412  lock (m_PendingRequests)
413  {
414  cresult.AddRange(m_contactResults);
415  m_contactResults.Clear();
416  }
417 
418  ((ProbePlaneCallback)req.callbackMethod)(cresult);
419  }
420 
425  private void doGeomRay(ODERayRequest req, IntPtr geom)
426  {
427  // Collide test
428  d.SpaceCollide2(ray, geom, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test
429 
430  if (req.callbackMethod is RaycastCallback)
431  {
432  // Define default results
433  bool hitYN = false;
434  uint hitConsumerID = 0;
435  float distance = float.MaxValue;
436  Vector3 closestcontact = Vector3.Zero;
437  Vector3 snormal = Vector3.Zero;
438 
439  // Find closest contact and object.
440  lock (m_contactResults)
441  {
442  foreach (ContactResult cResult in m_contactResults)
443  {
444  if(cResult.Depth < distance )
445  {
446  closestcontact = cResult.Pos;
447  hitConsumerID = cResult.ConsumerID;
448  distance = cResult.Depth;
449  snormal = cResult.Normal;
450  }
451  }
452  m_contactResults.Clear();
453  }
454 
455  if (distance > 0 && distance < float.MaxValue)
456  hitYN = true;
457 
458  ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
459  }
460  else
461  {
462  List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
463  lock (m_PendingRequests)
464  {
465  cresult.AddRange(m_contactResults);
466  m_contactResults.Clear();
467  }
468  ((RayCallback)req.callbackMethod)(cresult);
469  }
470  }
471 
472  private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom)
473  {
474  IntPtr ContactgeomsArray = m_scene.ContactgeomsArray;
475  if (ContactgeomsArray == IntPtr.Zero || index >= CollisionContactGeomsPerTest)
476  return false;
477 
478  IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf));
479  newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom));
480  return true;
481  }
482 
483  // This is the standard Near. g1 is the ray
484  private void near(IntPtr space, IntPtr g1, IntPtr g2)
485  {
486  if (g2 == IntPtr.Zero || g1 == g2)
487  return;
488 
489  if (m_contactResults.Count >= CurrentMaxCount)
490  return;
491 
492  if (d.GeomIsSpace(g2))
493  {
494  try
495  {
496  d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
497  }
498  catch (Exception e)
499  {
500  m_log.WarnFormat("[PHYSICS Ray]: Unable to Space collide test an object: {0}", e.Message);
501  }
502  return;
503  }
504 
505  int count = 0;
506  try
507  {
508  count = d.CollidePtr(g1, g2, CollisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
509  }
510  catch (Exception e)
511  {
512  m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
513  return;
514  }
515 
516  if (count == 0)
517  return;
518 /*
519  uint cat1 = d.GeomGetCategoryBits(g1);
520  uint cat2 = d.GeomGetCategoryBits(g2);
521  uint col1 = d.GeomGetCollideBits(g1);
522  uint col2 = d.GeomGetCollideBits(g2);
523 */
524 
525  uint ID = 0;
526  PhysicsActor p2 = null;
527 
528  m_scene.actor_name_map.TryGetValue(g2, out p2);
529 
530  if (p2 == null)
531  return;
532 
533  switch (p2.PhysicsActorType)
534  {
535  case (int)ActorTypes.Prim:
536 
537  RayFilterFlags thisFlags;
538 
539  if (p2.IsPhysical)
540  thisFlags = RayFilterFlags.physical;
541  else
542  thisFlags = RayFilterFlags.nonphysical;
543 
544  if (p2.Phantom)
545  thisFlags |= RayFilterFlags.phantom;
546 
547  if (p2.IsVolumeDtc)
548  thisFlags |= RayFilterFlags.volumedtc;
549 
550  if ((thisFlags & CurrentRayFilter) == 0)
551  return;
552 
553  ID = ((OdePrim)p2).LocalID;
554  break;
555 
556  case (int)ActorTypes.Agent:
557 
558  if ((CurrentRayFilter & RayFilterFlags.agent) == 0)
559  return;
560  else
561  ID = ((OdeCharacter)p2).LocalID;
562  break;
563 
564  case (int)ActorTypes.Ground:
565 
566  if ((CurrentRayFilter & RayFilterFlags.land) == 0)
567  return;
568  break;
569 
570  case (int)ActorTypes.Water:
571 
572  if ((CurrentRayFilter & RayFilterFlags.water) == 0)
573  return;
574  break;
575 
576  default:
577  break;
578  }
579 
580  d.ContactGeom curcontact = new d.ContactGeom();
581 
582  // closestHit for now only works for meshs, so must do it for others
583  if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
584  {
585  // Loop all contacts, build results.
586  for (int i = 0; i < count; i++)
587  {
588  if (!GetCurContactGeom(i, ref curcontact))
589  break;
590 
591  ContactResult collisionresult = new ContactResult();
592  collisionresult.ConsumerID = ID;
593  collisionresult.Pos.X = curcontact.pos.X;
594  collisionresult.Pos.Y = curcontact.pos.Y;
595  collisionresult.Pos.Z = curcontact.pos.Z;
596  collisionresult.Depth = curcontact.depth;
597  collisionresult.Normal.X = curcontact.normal.X;
598  collisionresult.Normal.Y = curcontact.normal.Y;
599  collisionresult.Normal.Z = curcontact.normal.Z;
600  lock (m_contactResults)
601  {
602  m_contactResults.Add(collisionresult);
603  if (m_contactResults.Count >= CurrentMaxCount)
604  return;
605  }
606  }
607  }
608  else
609  {
610  // keep only closest contact
611  ContactResult collisionresult = new ContactResult();
612  collisionresult.ConsumerID = ID;
613  collisionresult.Depth = float.MaxValue;
614 
615  for (int i = 0; i < count; i++)
616  {
617  if (!GetCurContactGeom(i, ref curcontact))
618  break;
619 
620  if (curcontact.depth < collisionresult.Depth)
621  {
622  collisionresult.Pos.X = curcontact.pos.X;
623  collisionresult.Pos.Y = curcontact.pos.Y;
624  collisionresult.Pos.Z = curcontact.pos.Z;
625  collisionresult.Depth = curcontact.depth;
626  collisionresult.Normal.X = curcontact.normal.X;
627  collisionresult.Normal.Y = curcontact.normal.Y;
628  collisionresult.Normal.Z = curcontact.normal.Z;
629  }
630  }
631 
632  if (collisionresult.Depth != float.MaxValue)
633  {
634  lock (m_contactResults)
635  m_contactResults.Add(collisionresult);
636  }
637  }
638  }
639 
643  internal void Dispose()
644  {
645  m_scene = null;
646  if (ray != IntPtr.Zero)
647  {
648  d.GeomDestroy(ray);
649  ray = IntPtr.Zero;
650  }
651  if (Box != IntPtr.Zero)
652  {
653  d.GeomDestroy(Box);
654  Box = IntPtr.Zero;
655  }
656  if (Sphere != IntPtr.Zero)
657  {
658  d.GeomDestroy(Sphere);
659  Sphere = IntPtr.Zero;
660  }
661  if (Plane != IntPtr.Zero)
662  {
663  d.GeomDestroy(Plane);
664  Plane = IntPtr.Zero;
665  }
666  }
667  }
668 
669  public struct ODERayRequest
670  {
672  public Vector3 Origin;
673  public Vector3 Normal;
674  public int Count;
675  public float length;
676  public object callbackMethod;
678  public Quaternion orientation;
679  }
680 }
Processes raycast requests as ODE is in a state to be able to do them. This ensures that it's thread ...
delegate void ProbePlaneCallback(List< ContactResult > list)
delegate void RayCallback(List< ContactResult > list)
delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal)
delegate void ProbeBoxCallback(List< ContactResult > list)
delegate void ProbeSphereCallback(List< ContactResult > list)
int ProcessQueuedRequests()
Process all queued raycast requests