aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs')
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs443
1 files changed, 443 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..4b3f83b
--- /dev/null
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs
@@ -0,0 +1,443 @@
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 OpenMetaverse;
34using OpenSim.Region.Physics.Manager;
35using OdeAPI;
36using log4net;
37
38namespace OpenSim.Region.Physics.OdePlugin
39{
40 /// <summary>
41 /// Processes raycast requests as ODE is in a state to be able to do them.
42 /// This ensures that it's thread safe and there will be no conflicts.
43 /// Requests get returned by a different thread then they were requested by.
44 /// </summary>
45 public class ODERayCastRequestManager
46 {
47 /// <summary>
48 /// Pending ray requests
49 /// </summary>
50 protected OpenSim.Framework.LocklessQueue<ODERayRequest> m_PendingRequests = new OpenSim.Framework.LocklessQueue<ODERayRequest>();
51
52 /// <summary>
53 /// Scene that created this object.
54 /// </summary>
55 private OdeScene m_scene;
56
57 IntPtr ray;
58
59 private const int ColisionContactGeomsPerTest = 5;
60
61 /// <summary>
62 /// ODE near callback delegate
63 /// </summary>
64 private d.NearCallback nearCallback;
65 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
66 private List<ContactResult> m_contactResults = new List<ContactResult>();
67
68 public ODERayCastRequestManager(OdeScene pScene)
69 {
70 m_scene = pScene;
71 nearCallback = near;
72 ray = d.CreateRay(IntPtr.Zero, 1.0f);
73 }
74
75 /// <summary>
76 /// Queues a raycast
77 /// </summary>
78 /// <param name="position">Origin of Ray</param>
79 /// <param name="direction">Ray normal</param>
80 /// <param name="length">Ray length</param>
81 /// <param name="retMethod">Return method to send the results</param>
82 public void QueueRequest(Vector3 position, Vector3 direction, float length, RayCallback retMethod)
83 {
84 ODERayRequest req = new ODERayRequest();
85 req.geom = IntPtr.Zero;
86 req.callbackMethod = retMethod;
87 req.Count = 0;
88 req.length = length;
89 req.Normal = direction;
90 req.Origin = position;
91
92 m_PendingRequests.Enqueue(req);
93 }
94
95 public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, RayCallback retMethod)
96 {
97 ODERayRequest req = new ODERayRequest();
98 req.geom = geom;
99 req.callbackMethod = retMethod;
100 req.length = length;
101 req.Normal = direction;
102 req.Origin = position;
103 req.Count = 0;
104
105 m_PendingRequests.Enqueue(req);
106 }
107
108 public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
109 {
110 ODERayRequest req = new ODERayRequest();
111 req.geom = IntPtr.Zero;
112 req.callbackMethod = retMethod;
113 req.Count = 0;
114 req.length = length;
115 req.Normal = direction;
116 req.Origin = position;
117
118 m_PendingRequests.Enqueue(req);
119 }
120
121 public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
122 {
123 ODERayRequest req = new ODERayRequest();
124 req.geom = geom;
125 req.callbackMethod = retMethod;
126 req.length = length;
127 req.Normal = direction;
128 req.Origin = position;
129 req.Count = 0;
130
131 m_PendingRequests.Enqueue(req);
132 }
133
134 /// <summary>
135 /// Queues a raycast
136 /// </summary>
137 /// <param name="position">Origin of Ray</param>
138 /// <param name="direction">Ray normal</param>
139 /// <param name="length">Ray length</param>
140 /// <param name="count"></param>
141 /// <param name="retMethod">Return method to send the results</param>
142 public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
143 {
144 ODERayRequest req = new ODERayRequest();
145 req.geom = IntPtr.Zero;
146 req.callbackMethod = retMethod;
147 req.length = length;
148 req.Normal = direction;
149 req.Origin = position;
150 req.Count = count;
151
152 m_PendingRequests.Enqueue(req);
153 }
154
155 public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
156 {
157 ODERayRequest req = new ODERayRequest();
158 req.geom = geom;
159 req.callbackMethod = retMethod;
160 req.length = length;
161 req.Normal = direction;
162 req.Origin = position;
163 req.Count = count;
164
165 m_PendingRequests.Enqueue(req);
166 }
167
168 public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RaycastCallback retMethod)
169 {
170 ODERayRequest req = new ODERayRequest();
171 req.geom = IntPtr.Zero;
172 req.callbackMethod = retMethod;
173 req.length = length;
174 req.Normal = direction;
175 req.Origin = position;
176 req.Count = count;
177
178 m_PendingRequests.Enqueue(req);
179 }
180
181 public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, int count, RaycastCallback retMethod)
182 {
183 ODERayRequest req = new ODERayRequest();
184 req.geom = geom;
185 req.callbackMethod = retMethod;
186 req.length = length;
187 req.Normal = direction;
188 req.Origin = position;
189 req.Count = count;
190
191 m_PendingRequests.Enqueue(req);
192 }
193
194 /// <summary>
195 /// Process all queued raycast requests
196 /// </summary>
197 /// <returns>Time in MS the raycasts took to process.</returns>
198 public int ProcessQueuedRequests()
199 {
200 int time = System.Environment.TickCount;
201
202 if (m_PendingRequests.Count <= 0)
203 return 0;
204
205 if (m_scene.ContactgeomsArray == IntPtr.Zero) // oops something got wrong or scene isn't ready still
206 {
207 m_PendingRequests.Clear();
208 return 0;
209 }
210
211 ODERayRequest req;
212
213 int i = 50; // arbitary limit of processed tests per frame
214
215 while(m_PendingRequests.Dequeue(out req))
216 {
217 if (req.geom == IntPtr.Zero)
218 doSpaceRay(req);
219 else
220 doGeomRay(req);
221 if(--i < 0)
222 break;
223 }
224
225 lock (m_contactResults)
226 m_contactResults.Clear();
227
228 return System.Environment.TickCount - time;
229 }
230 /// <summary>
231 /// Method that actually initiates the raycast with full top space
232 /// </summary>
233 /// <param name="req"></param>
234 private void doSpaceRay(ODERayRequest req)
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
241 // Collide test
242 d.SpaceCollide2(m_scene.TopSpace, ray, IntPtr.Zero, nearCallback);
243
244 // Remove Ray
245// d.GeomDestroy(ray);
246
247 if (req.callbackMethod == null)
248 return;
249
250 if (req.callbackMethod is RaycastCallback)
251 {
252 // Define default results
253 bool hitYN = false;
254 uint hitConsumerID = 0;
255 float distance = 999999999999f;
256 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
257 Vector3 snormal = Vector3.Zero;
258
259 // Find closest contact and object.
260 lock (m_contactResults)
261 {
262 foreach (ContactResult cResult in m_contactResults)
263 {
264 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
265 {
266 closestcontact = cResult.Pos;
267 hitConsumerID = cResult.ConsumerID;
268 distance = cResult.Depth;
269 hitYN = true;
270 snormal = cResult.Normal;
271 }
272 }
273 m_contactResults.Clear();
274 }
275
276 ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
277 }
278 else
279 {
280 ((RayCallback)req.callbackMethod)(m_contactResults);
281 lock (m_PendingRequests)
282 m_contactResults.Clear();
283 }
284 }
285
286 /// <summary>
287 /// Method that actually initiates the raycast with a geom
288 /// </summary>
289 /// <param name="req"></param>
290 private void doGeomRay(ODERayRequest req)
291 {
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
298 d.SpaceCollide2(req.geom, ray, 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
306 if (req.callbackMethod is RaycastCallback)
307 {
308 // Define default results
309 bool hitYN = false;
310 uint hitConsumerID = 0;
311 float distance = 999999999999f;
312 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
313 Vector3 snormal = Vector3.Zero;
314
315 // Find closest contact and object.
316 lock (m_contactResults)
317 {
318 foreach (ContactResult cResult in m_contactResults)
319 {
320 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
321 {
322 closestcontact = cResult.Pos;
323 hitConsumerID = cResult.ConsumerID;
324 distance = cResult.Depth;
325 hitYN = true;
326 snormal = cResult.Normal;
327 }
328 }
329 m_contactResults.Clear();
330 }
331
332 ((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
333 }
334 else
335 {
336 ((RayCallback)req.callbackMethod)(m_contactResults);
337 lock (m_PendingRequests)
338 m_contactResults.Clear();
339 }
340 }
341
342 private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom)
343 {
344 IntPtr ContactgeomsArray = m_scene.ContactgeomsArray;
345 if (ContactgeomsArray == IntPtr.Zero || index >= ColisionContactGeomsPerTest)
346 return false;
347
348 IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf));
349 newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom));
350 return true;
351 }
352
353 // This is the standard Near. g2 is the ray
354 private void near(IntPtr space, IntPtr g1, IntPtr g2)
355 {
356 //Don't test against heightfield Geom, or you'll be sorry!
357 // Exclude heightfield geom
358
359 if (g1 == IntPtr.Zero || g1 == g2)
360 return;
361
362 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass)
363 return;
364
365 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
366 if (d.GeomIsSpace(g1))
367 {
368 try
369 {
370 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
371 }
372 catch (Exception e)
373 {
374 m_log.WarnFormat("[PHYSICS Ray]: Unable to Space collide test an object: {0}", e.Message);
375 }
376 return;
377 }
378
379 int count = 0;
380 try
381 {
382 count = d.CollidePtr(g1, g2, ColisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
383 }
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)
389 {
390 m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
391 return;
392 }
393
394 if (count == 0)
395 return;
396
397 PhysicsActor p1 = null;
398
399 if (g1 != IntPtr.Zero)
400 m_scene.actor_name_map.TryGetValue(g1, out p1);
401
402 d.ContactGeom curcontact = new d.ContactGeom();
403 // Loop over contacts, build results.
404 for (int i = 0; i < count; i++)
405 {
406 if (!GetCurContactGeom(i, ref curcontact))
407 break;
408 if (p1 != null) {
409 if (p1 is OdePrim)
410 {
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);
415 collisionresult.Depth = curcontact.depth;
416 collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y,
417 curcontact.normal.Z);
418 lock (m_contactResults)
419 m_contactResults.Add(collisionresult);
420 }
421 }
422 }
423 }
424
425 /// <summary>
426 /// Dereference the creator scene so that it can be garbage collected if needed.
427 /// </summary>
428 internal void Dispose()
429 {
430 m_scene = null;
431 }
432 }
433
434 public struct ODERayRequest
435 {
436 public IntPtr geom;
437 public Vector3 Origin;
438 public Vector3 Normal;
439 public int Count;
440 public float length;
441 public object callbackMethod;
442 }
443} \ No newline at end of file