aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
diff options
context:
space:
mode:
authorTeravus Ovares2009-07-19 02:32:02 +0000
committerTeravus Ovares2009-07-19 02:32:02 +0000
commit08819bcbea9012d67cc4cb44e4d7ec7e5837bac6 (patch)
tree9158d1b42f1563db2294cfce5e85f41f1345d613 /OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
parentThank you, otakup0pe, for a patch that enables basic auth with LSL (diff)
downloadopensim-SC-08819bcbea9012d67cc4cb44e4d7ec7e5837bac6.zip
opensim-SC-08819bcbea9012d67cc4cb44e4d7ec7e5837bac6.tar.gz
opensim-SC-08819bcbea9012d67cc4cb44e4d7ec7e5837bac6.tar.bz2
opensim-SC-08819bcbea9012d67cc4cb44e4d7ec7e5837bac6.tar.xz
* Created a way that the OpenSimulator scene can ask the physics scene to do a raycast test safely.
* Test for prim obstructions between the avatar and camera. If there are obstructions, inform the client to move the camera closer. This makes it so that walls and objects don't obstruct your view while you're moving around. Try walking inside a hollowed tori. You'll see how much easier it is now because your camera automatically moves closer so you can still see. * Created a way to know if the user's camera is alt + cammed or just following the avatar. * Changes IClientAPI interface by adding SendCameraConstraint(Vector4 CameraConstraint)
Diffstat (limited to 'OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs')
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs295
1 files changed, 295 insertions, 0 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}