aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/OdePlugin
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs295
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdePlugin.cs23
2 files changed, 317 insertions, 1 deletions
diff --git a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
new file mode 100644
index 0000000..3a4bb02
--- /dev/null
+++ b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
@@ -0,0 +1,295 @@
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 Ode.NET;
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 Raycast Requests
49 /// </summary>
50 protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>();
51
52 /// <summary>
53 /// Scene that created this object.
54 /// </summary>
55 private OdeScene m_scene;
56
57 /// <summary>
58 /// ODE contact array to be filled by the collision testing
59 /// </summary>
60 d.ContactGeom[] contacts = new d.ContactGeom[5];
61
62 /// <summary>
63 /// ODE near callback delegate
64 /// </summary>
65 private d.NearCallback nearCallback;
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private List<ContactResult> m_contactResults = new List<ContactResult>();
68
69
70 public ODERayCastRequestManager( OdeScene pScene)
71 {
72 m_scene = pScene;
73 nearCallback = near;
74
75 }
76
77 /// <summary>
78 /// Queues a raycast
79 /// </summary>
80 /// <param name="position">Origin of Ray</param>
81 /// <param name="direction">Ray normal</param>
82 /// <param name="length">Ray length</param>
83 /// <param name="retMethod">Return method to send the results</param>
84 public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
85 {
86 lock (m_PendingRequests)
87 {
88 ODERayCastRequest req = new ODERayCastRequest();
89 req.callbackMethod = retMethod;
90 req.length = length;
91 req.Normal = direction;
92 req.Origin = position;
93
94 m_PendingRequests.Add(req);
95 }
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 int time = System.Environment.TickCount;
105 lock (m_PendingRequests)
106 {
107 if (m_PendingRequests.Count > 0)
108 {
109 foreach (ODERayCastRequest req in m_PendingRequests)
110 {
111 if (req.callbackMethod != null) // quick optimization here, don't raycast
112 RayCast(req); // if there isn't anyone to send results to
113
114 }
115
116 m_PendingRequests.Clear();
117 }
118 }
119
120 lock (m_contactResults)
121 m_contactResults.Clear();
122
123 return System.Environment.TickCount - time;
124 }
125
126 /// <summary>
127 /// Method that actually initiates the raycast
128 /// </summary>
129 /// <param name="req"></param>
130 private void RayCast(ODERayCastRequest req)
131 {
132 // Create the ray
133 IntPtr ray = d.CreateRay(m_scene.space, req.length);
134 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
135
136 // Collide test
137 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
138
139 // Remove Ray
140 d.GeomDestroy(ray);
141
142
143 // Define default results
144 bool hitYN = false;
145 uint hitConsumerID = 0;
146 float distance = 999999999999f;
147 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
148
149 // Find closest contact and object.
150 lock (m_contactResults)
151 {
152 foreach(ContactResult cResult in m_contactResults)
153 {
154 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
155 {
156 closestcontact = cResult.Pos;
157 hitConsumerID = cResult.ConsumerID;
158 distance = cResult.Depth;
159 hitYN = true;
160 }
161 }
162
163 m_contactResults.Clear();
164 }
165
166 // Return results
167 if (req.callbackMethod != null)
168 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance);
169 }
170
171 // This is the standard Near. Uses space AABBs to speed up detection.
172 private void near(IntPtr space, IntPtr g1, IntPtr g2)
173 {
174 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
175 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
176 {
177 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
178 return;
179
180 // Separating static prim geometry spaces.
181 // We'll be calling near recursivly if one
182 // of them is a space to find all of the
183 // contact points in the space
184 try
185 {
186 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
187 }
188 catch (AccessViolationException)
189 {
190 m_log.Warn("[PHYSICS]: Unable to collide test a space");
191 return;
192 }
193 //Colliding a space or a geom with a space or a geom. so drill down
194
195 //Collide all geoms in each space..
196 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
197 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
198 return;
199 }
200
201 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
202 return;
203
204 int count = 0;
205 try
206 {
207
208 if (g1 == g2)
209 return; // Can't collide with yourself
210
211 lock (contacts)
212 {
213 count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
214 }
215 }
216 catch (SEHException)
217 {
218 m_log.Error("[PHYSICS]: 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.");
219 }
220 catch (Exception e)
221 {
222 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
223 return;
224 }
225
226 PhysicsActor p1 = null;
227 PhysicsActor p2 = null;
228
229 if (g1 != IntPtr.Zero)
230 m_scene.actor_name_map.TryGetValue(g1, out p1);
231
232 if (g2 != IntPtr.Zero)
233 m_scene.actor_name_map.TryGetValue(g1, out p2);
234
235 // Loop over contacts, build results.
236 for (int i = 0; i < count; i++)
237 {
238 if (p1 != null) {
239 if (p1 is OdePrim)
240 {
241 ContactResult collisionresult = new ContactResult();
242
243 collisionresult.ConsumerID = ((OdePrim)p1).m_localID;
244 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
245 collisionresult.Depth = contacts[i].depth;
246
247 lock (m_contactResults)
248 m_contactResults.Add(collisionresult);
249 }
250 }
251
252 if (p2 != null)
253 {
254 if (p2 is OdePrim)
255 {
256 ContactResult collisionresult = new ContactResult();
257
258 collisionresult.ConsumerID = ((OdePrim)p2).m_localID;
259 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
260 collisionresult.Depth = contacts[i].depth;
261
262 lock (m_contactResults)
263 m_contactResults.Add(collisionresult);
264 }
265 }
266
267
268 }
269
270 }
271
272 /// <summary>
273 /// Dereference the creator scene so that it can be garbage collected if needed.
274 /// </summary>
275 internal void Dispose()
276 {
277 m_scene = null;
278 }
279 }
280
281 public struct ODERayCastRequest
282 {
283 public Vector3 Origin;
284 public Vector3 Normal;
285 public float length;
286 public RaycastCallback callbackMethod;
287 }
288
289 public struct ContactResult
290 {
291 public Vector3 Pos;
292 public float Depth;
293 public uint ConsumerID;
294 }
295}
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
index 889afb6..87357a3 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
@@ -306,6 +306,8 @@ namespace OpenSim.Region.Physics.OdePlugin
306 306
307 private volatile int m_global_contactcount = 0; 307 private volatile int m_global_contactcount = 0;
308 308
309 private ODERayCastRequestManager m_rayCastManager;
310
309 /// <summary> 311 /// <summary>
310 /// Initiailizes the scene 312 /// Initiailizes the scene
311 /// Sets many properties that ODE requires to be stable 313 /// Sets many properties that ODE requires to be stable
@@ -321,7 +323,7 @@ namespace OpenSim.Region.Physics.OdePlugin
321 nearCallback = near; 323 nearCallback = near;
322 triCallback = TriCallback; 324 triCallback = TriCallback;
323 triArrayCallback = TriArrayCallback; 325 triArrayCallback = TriArrayCallback;
324 326 m_rayCastManager = new ODERayCastRequestManager(this);
325 lock (OdeLock) 327 lock (OdeLock)
326 { 328 {
327 // Create the world and the first space 329 // Create the world and the first space
@@ -2833,6 +2835,8 @@ namespace OpenSim.Region.Physics.OdePlugin
2833 //if ((framecount % m_randomizeWater) == 0) 2835 //if ((framecount % m_randomizeWater) == 0)
2834 // randomizeWater(waterlevel); 2836 // randomizeWater(waterlevel);
2835 2837
2838 int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2839
2836 collision_optimized(timeStep); 2840 collision_optimized(timeStep);
2837 2841
2838 lock (_collisionEventPrim) 2842 lock (_collisionEventPrim)
@@ -3377,6 +3381,9 @@ namespace OpenSim.Region.Physics.OdePlugin
3377 3381
3378 public override void Dispose() 3382 public override void Dispose()
3379 { 3383 {
3384 m_rayCastManager.Dispose();
3385 m_rayCastManager = null;
3386
3380 lock (OdeLock) 3387 lock (OdeLock)
3381 { 3388 {
3382 lock (_prims) 3389 lock (_prims)
@@ -3417,6 +3424,20 @@ namespace OpenSim.Region.Physics.OdePlugin
3417 } 3424 }
3418 return returncolliders; 3425 return returncolliders;
3419 } 3426 }
3427
3428 public override bool SupportsRayCast()
3429 {
3430 return true;
3431 }
3432
3433 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3434 {
3435 if (retMethod != null)
3436 {
3437 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3438 }
3439 }
3440
3420#if USE_DRAWSTUFF 3441#if USE_DRAWSTUFF
3421 // Keyboard callback 3442 // Keyboard callback
3422 public void command(int cmd) 3443 public void command(int cmd)