diff options
Diffstat (limited to 'OpenSim/Region/PhysicsModules/Ode')
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs | 62 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/ODEApi.cs | 2025 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs | 1408 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments | 630 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs | 981 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/ODEModule.cs | 89 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs | 3206 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs | 384 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs | 46 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/OdeScene.cs | 3541 | ||||
-rw-r--r-- | OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs | 153 |
11 files changed, 12525 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs new file mode 100644 index 0000000..3691d96 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs | |||
@@ -0,0 +1,62 @@ | |||
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.Reflection; | ||
29 | using System.Runtime.InteropServices; | ||
30 | using Mono.Addins; | ||
31 | |||
32 | // Information about this assembly is defined by the following | ||
33 | // attributes. | ||
34 | // | ||
35 | // change them to the information which is associated with the assembly | ||
36 | // you compile. | ||
37 | |||
38 | [assembly : AssemblyTitle("OdePlugin")] | ||
39 | [assembly : AssemblyDescription("")] | ||
40 | [assembly : AssemblyConfiguration("")] | ||
41 | [assembly : AssemblyCompany("http://opensimulator.org")] | ||
42 | [assembly : AssemblyProduct("OdePlugin")] | ||
43 | [assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] | ||
44 | [assembly : AssemblyTrademark("")] | ||
45 | [assembly : AssemblyCulture("")] | ||
46 | |||
47 | // This sets the default COM visibility of types in the assembly to invisible. | ||
48 | // If you need to expose a type to COM, use [ComVisible(true)] on that type. | ||
49 | |||
50 | [assembly : ComVisible(false)] | ||
51 | |||
52 | // The assembly version has following format : | ||
53 | // | ||
54 | // Major.Minor.Build.Revision | ||
55 | // | ||
56 | // You can specify all values by your own or you can build default build and revision | ||
57 | // numbers with the '*' character (the default): | ||
58 | |||
59 | [assembly : AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] | ||
60 | |||
61 | [assembly: Addin("OpenSim.Region.PhysicsModule.ODE", OpenSim.VersionInfo.VersionNumber)] | ||
62 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEApi.cs b/OpenSim/Region/PhysicsModules/Ode/ODEApi.cs new file mode 100644 index 0000000..c851b12 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODEApi.cs | |||
@@ -0,0 +1,2025 @@ | |||
1 | /* | ||
2 | * based on: | ||
3 | * Ode.NET - .NET bindings for ODE | ||
4 | * Jason Perkins (starkos@industriousone.com) | ||
5 | * Licensed under the New BSD | ||
6 | * Part of the OpenDynamicsEngine | ||
7 | Open Dynamics Engine | ||
8 | Copyright (c) 2001-2007, Russell L. Smith. | ||
9 | All rights reserved. | ||
10 | |||
11 | Redistribution and use in source and binary forms, with or without | ||
12 | modification, are permitted provided that the following conditions | ||
13 | are met: | ||
14 | |||
15 | Redistributions of source code must retain the above copyright notice, | ||
16 | this list of conditions and the following disclaimer. | ||
17 | |||
18 | Redistributions in binary form must reproduce the above copyright notice, | ||
19 | this list of conditions and the following disclaimer in the documentation | ||
20 | and/or other materials provided with the distribution. | ||
21 | |||
22 | Neither the names of ODE's copyright owner nor the names of its | ||
23 | contributors may be used to endorse or promote products derived from | ||
24 | this software without specific prior written permission. | ||
25 | |||
26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
30 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
31 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||
32 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
33 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
34 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
35 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
37 | * | ||
38 | * changes by opensim team; | ||
39 | * changes by Aurora team http://www.aurora-sim.org/ | ||
40 | * changes by Ubit Umarov | ||
41 | */ | ||
42 | |||
43 | using System; | ||
44 | using System.Runtime.InteropServices; | ||
45 | using System.Security; | ||
46 | using OMV = OpenMetaverse; | ||
47 | |||
48 | namespace OpenSim.Region.PhysicsModule.ODE | ||
49 | { | ||
50 | //#if dDOUBLE | ||
51 | // don't see much use in double precision with time steps of 20ms and 10 iterations used on opensim | ||
52 | // at least we save same memory and memory access time, FPU performance on intel usually is similar | ||
53 | // using dReal = System.Double; | ||
54 | //#else | ||
55 | using dReal = System.Single; | ||
56 | //#endif | ||
57 | |||
58 | public static class d | ||
59 | { | ||
60 | public static dReal Infinity = dReal.MaxValue; | ||
61 | public static int NTotalBodies = 0; | ||
62 | public static int NTotalGeoms = 0; | ||
63 | |||
64 | public const uint CONTACTS_UNIMPORTANT = 0x80000000; | ||
65 | |||
66 | #region Flags and Enumerations | ||
67 | |||
68 | [Flags] | ||
69 | public enum AllocateODEDataFlags : uint | ||
70 | { | ||
71 | BasicData = 0, | ||
72 | CollisionData = 0x00000001, | ||
73 | All = ~0u | ||
74 | } | ||
75 | |||
76 | [Flags] | ||
77 | public enum IniteODEFlags : uint | ||
78 | { | ||
79 | dInitFlagManualThreadCleanup = 0x00000001 | ||
80 | } | ||
81 | |||
82 | [Flags] | ||
83 | public enum ContactFlags : int | ||
84 | { | ||
85 | Mu2 = 0x001, | ||
86 | FDir1 = 0x002, | ||
87 | Bounce = 0x004, | ||
88 | SoftERP = 0x008, | ||
89 | SoftCFM = 0x010, | ||
90 | Motion1 = 0x020, | ||
91 | Motion2 = 0x040, | ||
92 | MotionN = 0x080, | ||
93 | Slip1 = 0x100, | ||
94 | Slip2 = 0x200, | ||
95 | Approx0 = 0x0000, | ||
96 | Approx1_1 = 0x1000, | ||
97 | Approx1_2 = 0x2000, | ||
98 | Approx1 = 0x3000 | ||
99 | } | ||
100 | |||
101 | public enum GeomClassID : int | ||
102 | { | ||
103 | SphereClass, | ||
104 | BoxClass, | ||
105 | CapsuleClass, | ||
106 | CylinderClass, | ||
107 | PlaneClass, | ||
108 | RayClass, | ||
109 | ConvexClass, | ||
110 | GeomTransformClass, | ||
111 | TriMeshClass, | ||
112 | HeightfieldClass, | ||
113 | FirstSpaceClass, | ||
114 | SimpleSpaceClass = FirstSpaceClass, | ||
115 | HashSpaceClass, | ||
116 | QuadTreeSpaceClass, | ||
117 | LastSpaceClass = QuadTreeSpaceClass, | ||
118 | ubtTerrainClass, | ||
119 | FirstUserClass, | ||
120 | LastUserClass = FirstUserClass + MaxUserClasses - 1, | ||
121 | NumClasses, | ||
122 | MaxUserClasses = 5 | ||
123 | } | ||
124 | |||
125 | public enum JointType : int | ||
126 | { | ||
127 | None, | ||
128 | Ball, | ||
129 | Hinge, | ||
130 | Slider, | ||
131 | Contact, | ||
132 | Universal, | ||
133 | Hinge2, | ||
134 | Fixed, | ||
135 | Null, | ||
136 | AMotor, | ||
137 | LMotor, | ||
138 | Plane2D | ||
139 | } | ||
140 | |||
141 | public enum JointParam : int | ||
142 | { | ||
143 | LoStop, | ||
144 | HiStop, | ||
145 | Vel, | ||
146 | FMax, | ||
147 | FudgeFactor, | ||
148 | Bounce, | ||
149 | CFM, | ||
150 | StopERP, | ||
151 | StopCFM, | ||
152 | SuspensionERP, | ||
153 | SuspensionCFM, | ||
154 | LoStop2 = 256, | ||
155 | HiStop2, | ||
156 | Vel2, | ||
157 | FMax2, | ||
158 | FudgeFactor2, | ||
159 | Bounce2, | ||
160 | CFM2, | ||
161 | StopERP2, | ||
162 | StopCFM2, | ||
163 | SuspensionERP2, | ||
164 | SuspensionCFM2, | ||
165 | LoStop3 = 512, | ||
166 | HiStop3, | ||
167 | Vel3, | ||
168 | FMax3, | ||
169 | FudgeFactor3, | ||
170 | Bounce3, | ||
171 | CFM3, | ||
172 | StopERP3, | ||
173 | StopCFM3, | ||
174 | SuspensionERP3, | ||
175 | SuspensionCFM3 | ||
176 | } | ||
177 | |||
178 | public enum dSweepAndPruneAxis : int | ||
179 | { | ||
180 | XYZ = ((0)|(1<<2)|(2<<4)), | ||
181 | XZY = ((0)|(2<<2)|(1<<4)), | ||
182 | YXZ = ((1)|(0<<2)|(2<<4)), | ||
183 | YZX = ((1)|(2<<2)|(0<<4)), | ||
184 | ZXY = ((2)|(0<<2)|(1<<4)), | ||
185 | ZYX = ((2)|(1<<2)|(0<<4)) | ||
186 | } | ||
187 | |||
188 | #endregion | ||
189 | |||
190 | #region Callbacks | ||
191 | |||
192 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
193 | public delegate int AABBTestFn(IntPtr o1, IntPtr o2, ref AABB aabb); | ||
194 | |||
195 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
196 | public delegate int ColliderFn(IntPtr o1, IntPtr o2, int flags, out ContactGeom contact, int skip); | ||
197 | |||
198 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
199 | public delegate void GetAABBFn(IntPtr geom, out AABB aabb); | ||
200 | |||
201 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
202 | public delegate ColliderFn GetColliderFnFn(int num); | ||
203 | |||
204 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
205 | public delegate void GeomDtorFn(IntPtr o); | ||
206 | |||
207 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
208 | public delegate dReal HeightfieldGetHeight(IntPtr p_user_data, int x, int z); | ||
209 | |||
210 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
211 | public delegate dReal OSTerrainGetHeight(IntPtr p_user_data, int x, int z); | ||
212 | |||
213 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
214 | public delegate void NearCallback(IntPtr data, IntPtr geom1, IntPtr geom2); | ||
215 | |||
216 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
217 | public delegate int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex); | ||
218 | |||
219 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
220 | public delegate int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount); | ||
221 | |||
222 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
223 | public delegate int TriRayCallback(IntPtr trimesh, IntPtr ray, int triangleIndex, dReal u, dReal v); | ||
224 | |||
225 | #endregion | ||
226 | |||
227 | #region Structs | ||
228 | |||
229 | [StructLayout(LayoutKind.Sequential)] | ||
230 | public struct AABB | ||
231 | { | ||
232 | public dReal MinX, MaxX; | ||
233 | public dReal MinY, MaxY; | ||
234 | public dReal MinZ, MaxZ; | ||
235 | } | ||
236 | |||
237 | |||
238 | [StructLayout(LayoutKind.Sequential)] | ||
239 | public struct Contact | ||
240 | { | ||
241 | public SurfaceParameters surface; | ||
242 | public ContactGeom geom; | ||
243 | public Vector3 fdir1; | ||
244 | public static readonly int unmanagedSizeOf = Marshal.SizeOf(typeof(Contact)); | ||
245 | } | ||
246 | |||
247 | |||
248 | [StructLayout(LayoutKind.Sequential)] | ||
249 | public struct ContactGeom | ||
250 | { | ||
251 | |||
252 | public Vector3 pos; | ||
253 | public Vector3 normal; | ||
254 | public dReal depth; | ||
255 | public IntPtr g1; | ||
256 | public IntPtr g2; | ||
257 | public int side1; | ||
258 | public int side2; | ||
259 | public static readonly int unmanagedSizeOf = Marshal.SizeOf(typeof(ContactGeom)); | ||
260 | } | ||
261 | |||
262 | [StructLayout(LayoutKind.Sequential)] | ||
263 | public struct GeomClass | ||
264 | { | ||
265 | public int bytes; | ||
266 | public GetColliderFnFn collider; | ||
267 | public GetAABBFn aabb; | ||
268 | public AABBTestFn aabb_test; | ||
269 | public GeomDtorFn dtor; | ||
270 | } | ||
271 | |||
272 | |||
273 | [StructLayout(LayoutKind.Sequential)] | ||
274 | public struct JointFeedback | ||
275 | { | ||
276 | public Vector3 f1; | ||
277 | public Vector3 t1; | ||
278 | public Vector3 f2; | ||
279 | public Vector3 t2; | ||
280 | } | ||
281 | |||
282 | |||
283 | [StructLayout(LayoutKind.Sequential)] | ||
284 | public struct Mass | ||
285 | { | ||
286 | public dReal mass; | ||
287 | public Vector4 c; | ||
288 | public Matrix3 I; | ||
289 | } | ||
290 | |||
291 | |||
292 | [StructLayout(LayoutKind.Sequential)] | ||
293 | public struct Matrix3 | ||
294 | { | ||
295 | public Matrix3(dReal m00, dReal m10, dReal m20, dReal m01, dReal m11, dReal m21, dReal m02, dReal m12, dReal m22) | ||
296 | { | ||
297 | M00 = m00; M10 = m10; M20 = m20; _m30 = 0.0f; | ||
298 | M01 = m01; M11 = m11; M21 = m21; _m31 = 0.0f; | ||
299 | M02 = m02; M12 = m12; M22 = m22; _m32 = 0.0f; | ||
300 | } | ||
301 | public dReal M00, M10, M20; | ||
302 | private dReal _m30; | ||
303 | public dReal M01, M11, M21; | ||
304 | private dReal _m31; | ||
305 | public dReal M02, M12, M22; | ||
306 | private dReal _m32; | ||
307 | } | ||
308 | |||
309 | [StructLayout(LayoutKind.Sequential)] | ||
310 | public struct Matrix4 | ||
311 | { | ||
312 | public Matrix4(dReal m00, dReal m10, dReal m20, dReal m30, | ||
313 | dReal m01, dReal m11, dReal m21, dReal m31, | ||
314 | dReal m02, dReal m12, dReal m22, dReal m32, | ||
315 | dReal m03, dReal m13, dReal m23, dReal m33) | ||
316 | { | ||
317 | M00 = m00; M10 = m10; M20 = m20; M30 = m30; | ||
318 | M01 = m01; M11 = m11; M21 = m21; M31 = m31; | ||
319 | M02 = m02; M12 = m12; M22 = m22; M32 = m32; | ||
320 | M03 = m03; M13 = m13; M23 = m23; M33 = m33; | ||
321 | } | ||
322 | public dReal M00, M10, M20, M30; | ||
323 | public dReal M01, M11, M21, M31; | ||
324 | public dReal M02, M12, M22, M32; | ||
325 | public dReal M03, M13, M23, M33; | ||
326 | } | ||
327 | |||
328 | [StructLayout(LayoutKind.Sequential)] | ||
329 | public struct Quaternion | ||
330 | { | ||
331 | public dReal W, X, Y, Z; | ||
332 | } | ||
333 | |||
334 | |||
335 | [StructLayout(LayoutKind.Sequential)] | ||
336 | public struct SurfaceParameters | ||
337 | { | ||
338 | public ContactFlags mode; | ||
339 | public dReal mu; | ||
340 | public dReal mu2; | ||
341 | public dReal bounce; | ||
342 | public dReal bounce_vel; | ||
343 | public dReal soft_erp; | ||
344 | public dReal soft_cfm; | ||
345 | public dReal motion1; | ||
346 | public dReal motion2; | ||
347 | public dReal motionN; | ||
348 | public dReal slip1; | ||
349 | public dReal slip2; | ||
350 | } | ||
351 | |||
352 | |||
353 | [StructLayout(LayoutKind.Sequential)] | ||
354 | public struct Vector3 | ||
355 | { | ||
356 | public Vector3(dReal x, dReal y, dReal z) | ||
357 | { | ||
358 | X = x; Y = y; Z = z; _w = 0.0f; | ||
359 | } | ||
360 | public dReal X, Y, Z; | ||
361 | private dReal _w; | ||
362 | } | ||
363 | |||
364 | |||
365 | [StructLayout(LayoutKind.Sequential)] | ||
366 | public struct Vector4 | ||
367 | { | ||
368 | public Vector4(dReal x, dReal y, dReal z, dReal w) | ||
369 | { | ||
370 | X = x; Y = y; Z = z; W = w; | ||
371 | } | ||
372 | public dReal X, Y, Z, W; | ||
373 | } | ||
374 | |||
375 | #endregion | ||
376 | |||
377 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dAllocateODEDataForThread"), SuppressUnmanagedCodeSecurity] | ||
378 | public static extern int AllocateODEDataForThread(uint ODEInitFlags); | ||
379 | |||
380 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dAreConnected"), SuppressUnmanagedCodeSecurity] | ||
381 | public static extern bool AreConnected(IntPtr b1, IntPtr b2); | ||
382 | |||
383 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dAreConnectedExcluding"), SuppressUnmanagedCodeSecurity] | ||
384 | public static extern bool AreConnectedExcluding(IntPtr b1, IntPtr b2, JointType joint_type); | ||
385 | |||
386 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyAddForce"), SuppressUnmanagedCodeSecurity] | ||
387 | public static extern void BodyAddForce(IntPtr body, dReal fx, dReal fy, dReal fz); | ||
388 | |||
389 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyAddForceAtPos"), SuppressUnmanagedCodeSecurity] | ||
390 | public static extern void BodyAddForceAtPos(IntPtr body, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); | ||
391 | |||
392 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyAddForceAtRelPos"), SuppressUnmanagedCodeSecurity] | ||
393 | public static extern void BodyAddForceAtRelPos(IntPtr body, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); | ||
394 | |||
395 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyAddRelForce"), SuppressUnmanagedCodeSecurity] | ||
396 | public static extern void BodyAddRelForce(IntPtr body, dReal fx, dReal fy, dReal fz); | ||
397 | |||
398 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyAddRelForceAtPos"), SuppressUnmanagedCodeSecurity] | ||
399 | public static extern void BodyAddRelForceAtPos(IntPtr body, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); | ||
400 | |||
401 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyAddRelForceAtRelPos"), SuppressUnmanagedCodeSecurity] | ||
402 | public static extern void BodyAddRelForceAtRelPos(IntPtr body, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); | ||
403 | |||
404 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyAddRelTorque"), SuppressUnmanagedCodeSecurity] | ||
405 | public static extern void BodyAddRelTorque(IntPtr body, dReal fx, dReal fy, dReal fz); | ||
406 | |||
407 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyAddTorque"), SuppressUnmanagedCodeSecurity] | ||
408 | public static extern void BodyAddTorque(IntPtr body, dReal fx, dReal fy, dReal fz); | ||
409 | |||
410 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyCopyPosition"), SuppressUnmanagedCodeSecurity] | ||
411 | public static extern void BodyCopyPosition(IntPtr body, out Vector3 pos); | ||
412 | |||
413 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyCopyPosition"), SuppressUnmanagedCodeSecurity] | ||
414 | public static extern void BodyCopyPosition(IntPtr body, out dReal X); | ||
415 | |||
416 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyCopyQuaternion"), SuppressUnmanagedCodeSecurity] | ||
417 | public static extern void BodyCopyQuaternion(IntPtr body, out Quaternion quat); | ||
418 | |||
419 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyCopyQuaternion"), SuppressUnmanagedCodeSecurity] | ||
420 | public static extern void BodyCopyQuaternion(IntPtr body, out dReal X); | ||
421 | |||
422 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyCopyRotation"), SuppressUnmanagedCodeSecurity] | ||
423 | public static extern void BodyCopyRotation(IntPtr body, out Matrix3 R); | ||
424 | |||
425 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyCopyRotation"), SuppressUnmanagedCodeSecurity] | ||
426 | public static extern void BodyCopyRotation(IntPtr body, out dReal M00); | ||
427 | |||
428 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyCreate"), SuppressUnmanagedCodeSecurity] | ||
429 | public static extern IntPtr BodyiCreate(IntPtr world); | ||
430 | public static IntPtr BodyCreate(IntPtr world) | ||
431 | { | ||
432 | NTotalBodies++; | ||
433 | return BodyiCreate(world); | ||
434 | } | ||
435 | |||
436 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyDestroy"), SuppressUnmanagedCodeSecurity] | ||
437 | public static extern void BodyiDestroy(IntPtr body); | ||
438 | public static void BodyDestroy(IntPtr body) | ||
439 | { | ||
440 | NTotalBodies--; | ||
441 | BodyiDestroy(body); | ||
442 | } | ||
443 | |||
444 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyDisable"), SuppressUnmanagedCodeSecurity] | ||
445 | public static extern void BodyDisable(IntPtr body); | ||
446 | |||
447 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyEnable"), SuppressUnmanagedCodeSecurity] | ||
448 | public static extern void BodyEnable(IntPtr body); | ||
449 | |||
450 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAutoDisableAngularThreshold"), SuppressUnmanagedCodeSecurity] | ||
451 | public static extern dReal BodyGetAutoDisableAngularThreshold(IntPtr body); | ||
452 | |||
453 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAutoDisableFlag"), SuppressUnmanagedCodeSecurity] | ||
454 | public static extern bool BodyGetAutoDisableFlag(IntPtr body); | ||
455 | |||
456 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAutoDisableDefaults"), SuppressUnmanagedCodeSecurity] | ||
457 | public static extern void BodyGetAutoDisableDefaults(IntPtr body); | ||
458 | |||
459 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAutoDisableLinearThreshold"), SuppressUnmanagedCodeSecurity] | ||
460 | public static extern dReal BodyGetAutoDisableLinearThreshold(IntPtr body); | ||
461 | |||
462 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAutoDisableSteps"), SuppressUnmanagedCodeSecurity] | ||
463 | public static extern int BodyGetAutoDisableSteps(IntPtr body); | ||
464 | |||
465 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAutoDisableTime"), SuppressUnmanagedCodeSecurity] | ||
466 | public static extern dReal BodyGetAutoDisableTime(IntPtr body); | ||
467 | |||
468 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAngularVel"), SuppressUnmanagedCodeSecurity] | ||
469 | public extern unsafe static Vector3* BodyGetAngularVelUnsafe(IntPtr body); | ||
470 | public static Vector3 BodyGetAngularVel(IntPtr body) | ||
471 | { | ||
472 | unsafe { return *(BodyGetAngularVelUnsafe(body)); } | ||
473 | } | ||
474 | |||
475 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetData"), SuppressUnmanagedCodeSecurity] | ||
476 | public static extern IntPtr BodyGetData(IntPtr body); | ||
477 | |||
478 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetFiniteRotationMode"), SuppressUnmanagedCodeSecurity] | ||
479 | public static extern int BodyGetFiniteRotationMode(IntPtr body); | ||
480 | |||
481 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetFiniteRotationAxis"), SuppressUnmanagedCodeSecurity] | ||
482 | public static extern void BodyGetFiniteRotationAxis(IntPtr body, out Vector3 result); | ||
483 | |||
484 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetForce"), SuppressUnmanagedCodeSecurity] | ||
485 | public extern unsafe static Vector3* BodyGetForceUnsafe(IntPtr body); | ||
486 | public static Vector3 BodyGetForce(IntPtr body) | ||
487 | { | ||
488 | unsafe { return *(BodyGetForceUnsafe(body)); } | ||
489 | } | ||
490 | |||
491 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetGravityMode"), SuppressUnmanagedCodeSecurity] | ||
492 | public static extern bool BodyGetGravityMode(IntPtr body); | ||
493 | |||
494 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetGyroscopicMode"), SuppressUnmanagedCodeSecurity] | ||
495 | public static extern int BodyGetGyroscopicMode(IntPtr body); | ||
496 | |||
497 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetJoint"), SuppressUnmanagedCodeSecurity] | ||
498 | public static extern IntPtr BodyGetJoint(IntPtr body, int index); | ||
499 | |||
500 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetLinearVel"), SuppressUnmanagedCodeSecurity] | ||
501 | public extern unsafe static Vector3* BodyGetLinearVelUnsafe(IntPtr body); | ||
502 | public static Vector3 BodyGetLinearVel(IntPtr body) | ||
503 | { | ||
504 | unsafe { return *(BodyGetLinearVelUnsafe(body)); } | ||
505 | } | ||
506 | |||
507 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetMass"), SuppressUnmanagedCodeSecurity] | ||
508 | public static extern void BodyGetMass(IntPtr body, out Mass mass); | ||
509 | |||
510 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetNumJoints"), SuppressUnmanagedCodeSecurity] | ||
511 | public static extern int BodyGetNumJoints(IntPtr body); | ||
512 | |||
513 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetPointVel"), SuppressUnmanagedCodeSecurity] | ||
514 | public static extern void BodyGetPointVel(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); | ||
515 | |||
516 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetPosition"), SuppressUnmanagedCodeSecurity] | ||
517 | public extern unsafe static Vector3* BodyGetPositionUnsafe(IntPtr body); | ||
518 | public static Vector3 BodyGetPosition(IntPtr body) | ||
519 | { | ||
520 | unsafe { return *(BodyGetPositionUnsafe(body)); } | ||
521 | } | ||
522 | |||
523 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetPosRelPoint"), SuppressUnmanagedCodeSecurity] | ||
524 | public static extern void BodyGetPosRelPoint(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); | ||
525 | |||
526 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
527 | public extern unsafe static Quaternion* BodyGetQuaternionUnsafe(IntPtr body); | ||
528 | public static Quaternion BodyGetQuaternion(IntPtr body) | ||
529 | { | ||
530 | unsafe { return *(BodyGetQuaternionUnsafe(body)); } | ||
531 | } | ||
532 | |||
533 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetRelPointPos"), SuppressUnmanagedCodeSecurity] | ||
534 | public static extern void BodyGetRelPointPos(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); | ||
535 | |||
536 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetRelPointVel"), SuppressUnmanagedCodeSecurity] | ||
537 | public static extern void BodyGetRelPointVel(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); | ||
538 | |||
539 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetRotation"), SuppressUnmanagedCodeSecurity] | ||
540 | public extern unsafe static Matrix3* BodyGetRotationUnsafe(IntPtr body); | ||
541 | public static Matrix3 BodyGetRotation(IntPtr body) | ||
542 | { | ||
543 | unsafe { return *(BodyGetRotationUnsafe(body)); } | ||
544 | } | ||
545 | |||
546 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetTorque"), SuppressUnmanagedCodeSecurity] | ||
547 | public extern unsafe static Vector3* BodyGetTorqueUnsafe(IntPtr body); | ||
548 | public static Vector3 BodyGetTorque(IntPtr body) | ||
549 | { | ||
550 | unsafe { return *(BodyGetTorqueUnsafe(body)); } | ||
551 | } | ||
552 | |||
553 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetWorld"), SuppressUnmanagedCodeSecurity] | ||
554 | public static extern IntPtr BodyGetWorld(IntPtr body); | ||
555 | |||
556 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetFirstGeom"), SuppressUnmanagedCodeSecurity] | ||
557 | public static extern IntPtr BodyGetFirstGeom(IntPtr body); | ||
558 | |||
559 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetNextGeom"), SuppressUnmanagedCodeSecurity] | ||
560 | public static extern IntPtr dBodyGetNextGeom(IntPtr Geom); | ||
561 | |||
562 | |||
563 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyIsEnabled"), SuppressUnmanagedCodeSecurity] | ||
564 | public static extern bool BodyIsEnabled(IntPtr body); | ||
565 | |||
566 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAngularVel"), SuppressUnmanagedCodeSecurity] | ||
567 | public static extern void BodySetAngularVel(IntPtr body, dReal x, dReal y, dReal z); | ||
568 | |||
569 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAutoDisableAngularThreshold"), SuppressUnmanagedCodeSecurity] | ||
570 | public static extern void BodySetAutoDisableAngularThreshold(IntPtr body, dReal angular_threshold); | ||
571 | |||
572 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAutoDisableDefaults"), SuppressUnmanagedCodeSecurity] | ||
573 | public static extern void BodySetAutoDisableDefaults(IntPtr body); | ||
574 | |||
575 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAutoDisableFlag"), SuppressUnmanagedCodeSecurity] | ||
576 | public static extern void BodySetAutoDisableFlag(IntPtr body, bool do_auto_disable); | ||
577 | |||
578 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAutoDisableLinearThreshold"), SuppressUnmanagedCodeSecurity] | ||
579 | public static extern void BodySetAutoDisableLinearThreshold(IntPtr body, dReal linear_threshold); | ||
580 | |||
581 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAutoDisableSteps"), SuppressUnmanagedCodeSecurity] | ||
582 | public static extern void BodySetAutoDisableSteps(IntPtr body, int steps); | ||
583 | |||
584 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAutoDisableTime"), SuppressUnmanagedCodeSecurity] | ||
585 | public static extern void BodySetAutoDisableTime(IntPtr body, dReal time); | ||
586 | |||
587 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetData"), SuppressUnmanagedCodeSecurity] | ||
588 | public static extern void BodySetData(IntPtr body, IntPtr data); | ||
589 | |||
590 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetFiniteRotationMode"), SuppressUnmanagedCodeSecurity] | ||
591 | public static extern void BodySetFiniteRotationMode(IntPtr body, int mode); | ||
592 | |||
593 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetFiniteRotationAxis"), SuppressUnmanagedCodeSecurity] | ||
594 | public static extern void BodySetFiniteRotationAxis(IntPtr body, dReal x, dReal y, dReal z); | ||
595 | |||
596 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetLinearDamping"), SuppressUnmanagedCodeSecurity] | ||
597 | public static extern void BodySetLinearDamping(IntPtr body, dReal scale); | ||
598 | |||
599 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAngularDamping"), SuppressUnmanagedCodeSecurity] | ||
600 | public static extern void BodySetAngularDamping(IntPtr body, dReal scale); | ||
601 | |||
602 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetLinearDamping"), SuppressUnmanagedCodeSecurity] | ||
603 | public static extern dReal BodyGetLinearDamping(IntPtr body); | ||
604 | |||
605 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAngularDamping"), SuppressUnmanagedCodeSecurity] | ||
606 | public static extern dReal BodyGetAngularDamping(IntPtr body); | ||
607 | |||
608 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAngularDamping"), SuppressUnmanagedCodeSecurity] | ||
609 | public static extern void BodySetDamping(IntPtr body, dReal linear_scale, dReal angular_scale); | ||
610 | |||
611 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetAngularDampingThreshold"), SuppressUnmanagedCodeSecurity] | ||
612 | public static extern void BodySetAngularDampingThreshold(IntPtr body, dReal threshold); | ||
613 | |||
614 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetLinearDampingThreshold"), SuppressUnmanagedCodeSecurity] | ||
615 | public static extern void BodySetLinearDampingThreshold(IntPtr body, dReal threshold); | ||
616 | |||
617 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetLinearDampingThreshold"), SuppressUnmanagedCodeSecurity] | ||
618 | public static extern dReal BodyGetLinearDampingThreshold(IntPtr body); | ||
619 | |||
620 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyGetAngularDampingThreshold"), SuppressUnmanagedCodeSecurity] | ||
621 | public static extern dReal BodyGetAngularDampingThreshold(IntPtr body); | ||
622 | |||
623 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetForce"), SuppressUnmanagedCodeSecurity] | ||
624 | public static extern void BodySetForce(IntPtr body, dReal x, dReal y, dReal z); | ||
625 | |||
626 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetGravityMode"), SuppressUnmanagedCodeSecurity] | ||
627 | public static extern void BodySetGravityMode(IntPtr body, bool mode); | ||
628 | |||
629 | /// <summary> | ||
630 | /// Sets the Gyroscopic term status on the body specified. | ||
631 | /// </summary> | ||
632 | /// <param name="body">Pointer to body</param> | ||
633 | /// <param name="enabled">NonZero enabled, Zero disabled</param> | ||
634 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetGyroscopicMode"), SuppressUnmanagedCodeSecurity] | ||
635 | public static extern void dBodySetGyroscopicMode(IntPtr body, int enabled); | ||
636 | |||
637 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetLinearVel"), SuppressUnmanagedCodeSecurity] | ||
638 | public static extern void BodySetLinearVel(IntPtr body, dReal x, dReal y, dReal z); | ||
639 | |||
640 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetMass"), SuppressUnmanagedCodeSecurity] | ||
641 | public static extern void BodySetMass(IntPtr body, ref Mass mass); | ||
642 | |||
643 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetPosition"), SuppressUnmanagedCodeSecurity] | ||
644 | public static extern void BodySetPosition(IntPtr body, dReal x, dReal y, dReal z); | ||
645 | |||
646 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
647 | public static extern void BodySetQuaternion(IntPtr body, ref Quaternion q); | ||
648 | |||
649 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
650 | public static extern void BodySetQuaternion(IntPtr body, ref dReal w); | ||
651 | |||
652 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetRotation"), SuppressUnmanagedCodeSecurity] | ||
653 | public static extern void BodySetRotation(IntPtr body, ref Matrix3 R); | ||
654 | |||
655 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetRotation"), SuppressUnmanagedCodeSecurity] | ||
656 | public static extern void BodySetRotation(IntPtr body, ref dReal M00); | ||
657 | |||
658 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodySetTorque"), SuppressUnmanagedCodeSecurity] | ||
659 | public static extern void BodySetTorque(IntPtr body, dReal x, dReal y, dReal z); | ||
660 | |||
661 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyVectorFromWorld"), SuppressUnmanagedCodeSecurity] | ||
662 | public static extern void BodyVectorFromWorld(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); | ||
663 | |||
664 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBodyVectorToWorld"), SuppressUnmanagedCodeSecurity] | ||
665 | public static extern void BodyVectorToWorld(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); | ||
666 | |||
667 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBoxBox"), SuppressUnmanagedCodeSecurity] | ||
668 | public static extern void BoxBox(ref Vector3 p1, ref Matrix3 R1, | ||
669 | ref Vector3 side1, ref Vector3 p2, | ||
670 | ref Matrix3 R2, ref Vector3 side2, | ||
671 | ref Vector3 normal, out dReal depth, out int return_code, | ||
672 | int maxc, out ContactGeom contact, int skip); | ||
673 | |||
674 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dBoxTouchesBox"), SuppressUnmanagedCodeSecurity] | ||
675 | public static extern void BoxTouchesBox(ref Vector3 _p1, ref Matrix3 R1, | ||
676 | ref Vector3 side1, ref Vector3 _p2, | ||
677 | ref Matrix3 R2, ref Vector3 side2); | ||
678 | |||
679 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCleanupODEAllDataForThread"), SuppressUnmanagedCodeSecurity] | ||
680 | public static extern void CleanupODEAllDataForThread(); | ||
681 | |||
682 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dClosestLineSegmentPoints"), SuppressUnmanagedCodeSecurity] | ||
683 | public static extern void ClosestLineSegmentPoints(ref Vector3 a1, ref Vector3 a2, | ||
684 | ref Vector3 b1, ref Vector3 b2, | ||
685 | ref Vector3 cp1, ref Vector3 cp2); | ||
686 | |||
687 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCloseODE"), SuppressUnmanagedCodeSecurity] | ||
688 | public static extern void CloseODE(); | ||
689 | |||
690 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCollide"), SuppressUnmanagedCodeSecurity] | ||
691 | public static extern int Collide(IntPtr o1, IntPtr o2, int flags, [In, Out] ContactGeom[] contact, int skip); | ||
692 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCollide"), SuppressUnmanagedCodeSecurity] | ||
693 | public static extern int CollidePtr(IntPtr o1, IntPtr o2, int flags, IntPtr contactgeomarray, int skip); | ||
694 | |||
695 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dConnectingJoint"), SuppressUnmanagedCodeSecurity] | ||
696 | public static extern IntPtr ConnectingJoint(IntPtr j1, IntPtr j2); | ||
697 | |||
698 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateBox"), SuppressUnmanagedCodeSecurity] | ||
699 | public static extern IntPtr CreateiBox(IntPtr space, dReal lx, dReal ly, dReal lz); | ||
700 | public static IntPtr CreateBox(IntPtr space, dReal lx, dReal ly, dReal lz) | ||
701 | { | ||
702 | NTotalGeoms++; | ||
703 | return CreateiBox(space, lx, ly, lz); | ||
704 | } | ||
705 | |||
706 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateCapsule"), SuppressUnmanagedCodeSecurity] | ||
707 | public static extern IntPtr CreateiCapsule(IntPtr space, dReal radius, dReal length); | ||
708 | public static IntPtr CreateCapsule(IntPtr space, dReal radius, dReal length) | ||
709 | { | ||
710 | NTotalGeoms++; | ||
711 | return CreateiCapsule(space, radius, length); | ||
712 | } | ||
713 | |||
714 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateConvex"), SuppressUnmanagedCodeSecurity] | ||
715 | public static extern IntPtr CreateiConvex(IntPtr space, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons); | ||
716 | public static IntPtr CreateConvex(IntPtr space, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons) | ||
717 | { | ||
718 | NTotalGeoms++; | ||
719 | return CreateiConvex(space, planes, planeCount, points, pointCount, polygons); | ||
720 | } | ||
721 | |||
722 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateCylinder"), SuppressUnmanagedCodeSecurity] | ||
723 | public static extern IntPtr CreateiCylinder(IntPtr space, dReal radius, dReal length); | ||
724 | public static IntPtr CreateCylinder(IntPtr space, dReal radius, dReal length) | ||
725 | { | ||
726 | NTotalGeoms++; | ||
727 | return CreateiCylinder(space, radius, length); | ||
728 | } | ||
729 | |||
730 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateHeightfield"), SuppressUnmanagedCodeSecurity] | ||
731 | public static extern IntPtr CreateiHeightfield(IntPtr space, IntPtr data, int bPlaceable); | ||
732 | public static IntPtr CreateHeightfield(IntPtr space, IntPtr data, int bPlaceable) | ||
733 | { | ||
734 | NTotalGeoms++; | ||
735 | return CreateiHeightfield(space, data, bPlaceable); | ||
736 | } | ||
737 | |||
738 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateOSTerrain"), SuppressUnmanagedCodeSecurity] | ||
739 | public static extern IntPtr CreateiOSTerrain(IntPtr space, IntPtr data, int bPlaceable); | ||
740 | public static IntPtr CreateOSTerrain(IntPtr space, IntPtr data, int bPlaceable) | ||
741 | { | ||
742 | NTotalGeoms++; | ||
743 | return CreateiOSTerrain(space, data, bPlaceable); | ||
744 | } | ||
745 | |||
746 | |||
747 | |||
748 | |||
749 | |||
750 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateGeom"), SuppressUnmanagedCodeSecurity] | ||
751 | public static extern IntPtr CreateiGeom(int classnum); | ||
752 | public static IntPtr CreateGeom(int classnum) | ||
753 | { | ||
754 | NTotalGeoms++; | ||
755 | return CreateiGeom(classnum); | ||
756 | } | ||
757 | |||
758 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateGeomClass"), SuppressUnmanagedCodeSecurity] | ||
759 | public static extern int CreateGeomClass(ref GeomClass classptr); | ||
760 | |||
761 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateGeomTransform"), SuppressUnmanagedCodeSecurity] | ||
762 | public static extern IntPtr CreateGeomTransform(IntPtr space); | ||
763 | |||
764 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreatePlane"), SuppressUnmanagedCodeSecurity] | ||
765 | public static extern IntPtr CreateiPlane(IntPtr space, dReal a, dReal b, dReal c, dReal d); | ||
766 | public static IntPtr CreatePlane(IntPtr space, dReal a, dReal b, dReal c, dReal d) | ||
767 | { | ||
768 | NTotalGeoms++; | ||
769 | return CreateiPlane(space, a, b, c, d); | ||
770 | } | ||
771 | |||
772 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateRay"), SuppressUnmanagedCodeSecurity] | ||
773 | public static extern IntPtr CreateiRay(IntPtr space, dReal length); | ||
774 | public static IntPtr CreateRay(IntPtr space, dReal length) | ||
775 | { | ||
776 | NTotalGeoms++; | ||
777 | return CreateiRay(space, length); | ||
778 | } | ||
779 | |||
780 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateSphere"), SuppressUnmanagedCodeSecurity] | ||
781 | public static extern IntPtr CreateiSphere(IntPtr space, dReal radius); | ||
782 | public static IntPtr CreateSphere(IntPtr space, dReal radius) | ||
783 | { | ||
784 | NTotalGeoms++; | ||
785 | return CreateiSphere(space, radius); | ||
786 | } | ||
787 | |||
788 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dCreateTriMesh"), SuppressUnmanagedCodeSecurity] | ||
789 | public static extern IntPtr CreateiTriMesh(IntPtr space, IntPtr data, | ||
790 | TriCallback callback, TriArrayCallback arrayCallback, TriRayCallback rayCallback); | ||
791 | public static IntPtr CreateTriMesh(IntPtr space, IntPtr data, | ||
792 | TriCallback callback, TriArrayCallback arrayCallback, TriRayCallback rayCallback) | ||
793 | { | ||
794 | NTotalGeoms++; | ||
795 | return CreateiTriMesh(space, data, callback, arrayCallback, rayCallback); | ||
796 | } | ||
797 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dDot"), SuppressUnmanagedCodeSecurity] | ||
798 | public static extern dReal Dot(ref dReal X0, ref dReal X1, int n); | ||
799 | |||
800 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dDQfromW"), SuppressUnmanagedCodeSecurity] | ||
801 | public static extern void DQfromW(dReal[] dq, ref Vector3 w, ref Quaternion q); | ||
802 | |||
803 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dFactorCholesky"), SuppressUnmanagedCodeSecurity] | ||
804 | public static extern int FactorCholesky(ref dReal A00, int n); | ||
805 | |||
806 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dFactorLDLT"), SuppressUnmanagedCodeSecurity] | ||
807 | public static extern void FactorLDLT(ref dReal A, out dReal d, int n, int nskip); | ||
808 | |||
809 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomBoxGetLengths"), SuppressUnmanagedCodeSecurity] | ||
810 | public static extern void GeomBoxGetLengths(IntPtr geom, out Vector3 len); | ||
811 | |||
812 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomBoxGetLengths"), SuppressUnmanagedCodeSecurity] | ||
813 | public static extern void GeomBoxGetLengths(IntPtr geom, out dReal x); | ||
814 | |||
815 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomBoxPointDepth"), SuppressUnmanagedCodeSecurity] | ||
816 | public static extern dReal GeomBoxPointDepth(IntPtr geom, dReal x, dReal y, dReal z); | ||
817 | |||
818 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomBoxSetLengths"), SuppressUnmanagedCodeSecurity] | ||
819 | public static extern void GeomBoxSetLengths(IntPtr geom, dReal x, dReal y, dReal z); | ||
820 | |||
821 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCapsuleGetParams"), SuppressUnmanagedCodeSecurity] | ||
822 | public static extern void GeomCapsuleGetParams(IntPtr geom, out dReal radius, out dReal length); | ||
823 | |||
824 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCapsulePointDepth"), SuppressUnmanagedCodeSecurity] | ||
825 | public static extern dReal GeomCapsulePointDepth(IntPtr geom, dReal x, dReal y, dReal z); | ||
826 | |||
827 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCapsuleSetParams"), SuppressUnmanagedCodeSecurity] | ||
828 | public static extern void GeomCapsuleSetParams(IntPtr geom, dReal radius, dReal length); | ||
829 | |||
830 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomClearOffset"), SuppressUnmanagedCodeSecurity] | ||
831 | public static extern void GeomClearOffset(IntPtr geom); | ||
832 | |||
833 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCopyOffsetPosition"), SuppressUnmanagedCodeSecurity] | ||
834 | public static extern IntPtr GeomCopyOffsetPosition(IntPtr geom, ref Vector3 pos); | ||
835 | |||
836 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCopyOffsetPosition"), SuppressUnmanagedCodeSecurity] | ||
837 | public static extern IntPtr GeomCopyOffsetPosition(IntPtr geom, ref dReal X); | ||
838 | |||
839 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetOffsetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
840 | public static extern void GeomCopyOffsetQuaternion(IntPtr geom, ref Quaternion Q); | ||
841 | |||
842 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetOffsetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
843 | public static extern void GeomCopyOffsetQuaternion(IntPtr geom, ref dReal X); | ||
844 | |||
845 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCopyOffsetRotation"), SuppressUnmanagedCodeSecurity] | ||
846 | public static extern IntPtr GeomCopyOffsetRotation(IntPtr geom, ref Matrix3 R); | ||
847 | |||
848 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCopyOffsetRotation"), SuppressUnmanagedCodeSecurity] | ||
849 | public static extern IntPtr GeomCopyOffsetRotation(IntPtr geom, ref dReal M00); | ||
850 | |||
851 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCopyPosition"), SuppressUnmanagedCodeSecurity] | ||
852 | public static extern void GeomCopyPosition(IntPtr geom, out Vector3 pos); | ||
853 | |||
854 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCopyPosition"), SuppressUnmanagedCodeSecurity] | ||
855 | public static extern void GeomCopyPosition(IntPtr geom, out dReal X); | ||
856 | |||
857 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCopyRotation"), SuppressUnmanagedCodeSecurity] | ||
858 | public static extern void GeomCopyRotation(IntPtr geom, out Matrix3 R); | ||
859 | |||
860 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCopyRotation"), SuppressUnmanagedCodeSecurity] | ||
861 | public static extern void GeomCopyRotation(IntPtr geom, out dReal M00); | ||
862 | |||
863 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCylinderGetParams"), SuppressUnmanagedCodeSecurity] | ||
864 | public static extern void GeomCylinderGetParams(IntPtr geom, out dReal radius, out dReal length); | ||
865 | |||
866 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomCylinderSetParams"), SuppressUnmanagedCodeSecurity] | ||
867 | public static extern void GeomCylinderSetParams(IntPtr geom, dReal radius, dReal length); | ||
868 | |||
869 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomDestroy"), SuppressUnmanagedCodeSecurity] | ||
870 | public static extern void GeomiDestroy(IntPtr geom); | ||
871 | public static void GeomDestroy(IntPtr geom) | ||
872 | { | ||
873 | NTotalGeoms--; | ||
874 | GeomiDestroy(geom); | ||
875 | } | ||
876 | |||
877 | |||
878 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomDisable"), SuppressUnmanagedCodeSecurity] | ||
879 | public static extern void GeomDisable(IntPtr geom); | ||
880 | |||
881 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomEnable"), SuppressUnmanagedCodeSecurity] | ||
882 | public static extern void GeomEnable(IntPtr geom); | ||
883 | |||
884 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetAABB"), SuppressUnmanagedCodeSecurity] | ||
885 | public static extern void GeomGetAABB(IntPtr geom, out AABB aabb); | ||
886 | |||
887 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetAABB"), SuppressUnmanagedCodeSecurity] | ||
888 | public static extern void GeomGetAABB(IntPtr geom, out dReal minX); | ||
889 | |||
890 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetBody"), SuppressUnmanagedCodeSecurity] | ||
891 | public static extern IntPtr GeomGetBody(IntPtr geom); | ||
892 | |||
893 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetCategoryBits"), SuppressUnmanagedCodeSecurity] | ||
894 | public static extern uint GeomGetCategoryBits(IntPtr geom); | ||
895 | |||
896 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetClassData"), SuppressUnmanagedCodeSecurity] | ||
897 | public static extern IntPtr GeomGetClassData(IntPtr geom); | ||
898 | |||
899 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetCollideBits"), SuppressUnmanagedCodeSecurity] | ||
900 | public static extern uint GeomGetCollideBits(IntPtr geom); | ||
901 | |||
902 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetClass"), SuppressUnmanagedCodeSecurity] | ||
903 | public static extern GeomClassID GeomGetClass(IntPtr geom); | ||
904 | |||
905 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetData"), SuppressUnmanagedCodeSecurity] | ||
906 | public static extern IntPtr GeomGetData(IntPtr geom); | ||
907 | |||
908 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetOffsetPosition"), SuppressUnmanagedCodeSecurity] | ||
909 | public extern unsafe static Vector3* GeomGetOffsetPositionUnsafe(IntPtr geom); | ||
910 | public static Vector3 GeomGetOffsetPosition(IntPtr geom) | ||
911 | { | ||
912 | unsafe { return *(GeomGetOffsetPositionUnsafe(geom)); } | ||
913 | } | ||
914 | |||
915 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetOffsetRotation"), SuppressUnmanagedCodeSecurity] | ||
916 | public extern unsafe static Matrix3* GeomGetOffsetRotationUnsafe(IntPtr geom); | ||
917 | public static Matrix3 GeomGetOffsetRotation(IntPtr geom) | ||
918 | { | ||
919 | unsafe { return *(GeomGetOffsetRotationUnsafe(geom)); } | ||
920 | } | ||
921 | |||
922 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetPosition"), SuppressUnmanagedCodeSecurity] | ||
923 | public extern unsafe static Vector3* GeomGetPositionUnsafe(IntPtr geom); | ||
924 | public static Vector3 GeomGetPosition(IntPtr geom) | ||
925 | { | ||
926 | unsafe { return *(GeomGetPositionUnsafe(geom)); } | ||
927 | } | ||
928 | public static OMV.Vector3 GeomGetPositionOMV(IntPtr geom) | ||
929 | { | ||
930 | Vector3 vtmp = GeomGetPosition(geom); | ||
931 | return new OMV.Vector3(vtmp.X, vtmp.Y, vtmp.Z); | ||
932 | } | ||
933 | |||
934 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
935 | public static extern void GeomCopyQuaternion(IntPtr geom, out Quaternion q); | ||
936 | public static OMV.Quaternion GeomGetQuaternionOMV(IntPtr geom) | ||
937 | { | ||
938 | Quaternion qtmp; | ||
939 | GeomCopyQuaternion(geom, out qtmp); | ||
940 | return new OMV.Quaternion(qtmp.X, qtmp.Y, qtmp.Z, qtmp.W); | ||
941 | } | ||
942 | |||
943 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
944 | public static extern void GeomCopyQuaternion(IntPtr geom, out dReal X); | ||
945 | |||
946 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetRotation"), SuppressUnmanagedCodeSecurity] | ||
947 | public extern unsafe static Matrix3* GeomGetRotationUnsafe(IntPtr geom); | ||
948 | public static Matrix3 GeomGetRotation(IntPtr geom) | ||
949 | { | ||
950 | unsafe { return *(GeomGetRotationUnsafe(geom)); } | ||
951 | } | ||
952 | |||
953 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetSpace"), SuppressUnmanagedCodeSecurity] | ||
954 | public static extern IntPtr GeomGetSpace(IntPtr geom); | ||
955 | |||
956 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildByte"), SuppressUnmanagedCodeSecurity] | ||
957 | public static extern void GeomHeightfieldDataBuildByte(IntPtr d, byte[] pHeightData, int bCopyHeightData, | ||
958 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
959 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
960 | |||
961 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildByte"), SuppressUnmanagedCodeSecurity] | ||
962 | public static extern void GeomHeightfieldDataBuildByte(IntPtr d, IntPtr pHeightData, int bCopyHeightData, | ||
963 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
964 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
965 | |||
966 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildCallback"), SuppressUnmanagedCodeSecurity] | ||
967 | public static extern void GeomHeightfieldDataBuildCallback(IntPtr d, IntPtr pUserData, HeightfieldGetHeight pCallback, | ||
968 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
969 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
970 | |||
971 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildShort"), SuppressUnmanagedCodeSecurity] | ||
972 | public static extern void GeomHeightfieldDataBuildShort(IntPtr d, ushort[] pHeightData, int bCopyHeightData, | ||
973 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
974 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
975 | |||
976 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildShort"), SuppressUnmanagedCodeSecurity] | ||
977 | public static extern void GeomHeightfieldDataBuildShort(IntPtr d, short[] pHeightData, int bCopyHeightData, | ||
978 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
979 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
980 | |||
981 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildShort"), SuppressUnmanagedCodeSecurity] | ||
982 | public static extern void GeomHeightfieldDataBuildShort(IntPtr d, IntPtr pHeightData, int bCopyHeightData, | ||
983 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
984 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
985 | |||
986 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildSingle"), SuppressUnmanagedCodeSecurity] | ||
987 | public static extern void GeomHeightfieldDataBuildSingle(IntPtr d, float[] pHeightData, int bCopyHeightData, | ||
988 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
989 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
990 | |||
991 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildSingle"), SuppressUnmanagedCodeSecurity] | ||
992 | public static extern void GeomHeightfieldDataBuildSingle(IntPtr d, IntPtr pHeightData, int bCopyHeightData, | ||
993 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
994 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
995 | |||
996 | |||
997 | |||
998 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildDouble"), SuppressUnmanagedCodeSecurity] | ||
999 | public static extern void GeomHeightfieldDataBuildDouble(IntPtr d, double[] pHeightData, int bCopyHeightData, | ||
1000 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
1001 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
1002 | |||
1003 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildDouble"), SuppressUnmanagedCodeSecurity] | ||
1004 | public static extern void GeomHeightfieldDataBuildDouble(IntPtr d, IntPtr pHeightData, int bCopyHeightData, | ||
1005 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
1006 | dReal scale, dReal offset, dReal thickness, int bWrap); | ||
1007 | |||
1008 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataCreate"), SuppressUnmanagedCodeSecurity] | ||
1009 | public static extern IntPtr GeomHeightfieldDataCreate(); | ||
1010 | |||
1011 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataDestroy"), SuppressUnmanagedCodeSecurity] | ||
1012 | public static extern void GeomHeightfieldDataDestroy(IntPtr d); | ||
1013 | |||
1014 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataSetBounds"), SuppressUnmanagedCodeSecurity] | ||
1015 | public static extern void GeomHeightfieldDataSetBounds(IntPtr d, dReal minHeight, dReal maxHeight); | ||
1016 | |||
1017 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldGetHeightfieldData"), SuppressUnmanagedCodeSecurity] | ||
1018 | public static extern IntPtr GeomHeightfieldGetHeightfieldData(IntPtr g); | ||
1019 | |||
1020 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldSetHeightfieldData"), SuppressUnmanagedCodeSecurity] | ||
1021 | public static extern void GeomHeightfieldSetHeightfieldData(IntPtr g, IntPtr d); | ||
1022 | |||
1023 | |||
1024 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomUbitTerrainDataBuild"), SuppressUnmanagedCodeSecurity] | ||
1025 | public static extern void GeomOSTerrainDataBuild(IntPtr d, float[] pHeightData, int bCopyHeightData, | ||
1026 | dReal sampleSize, int widthSamples, int depthSamples, | ||
1027 | dReal offset, dReal thickness, int bWrap); | ||
1028 | |||
1029 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomOSTerrainDataBuild"), SuppressUnmanagedCodeSecurity] | ||
1030 | public static extern void GeomOSTerrainDataBuild(IntPtr d, IntPtr pHeightData, int bCopyHeightData, | ||
1031 | dReal sampleSize, int widthSamples, int depthSamples, | ||
1032 | dReal thickness, int bWrap); | ||
1033 | |||
1034 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomOSTerrainDataCreate"), SuppressUnmanagedCodeSecurity] | ||
1035 | public static extern IntPtr GeomOSTerrainDataCreate(); | ||
1036 | |||
1037 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomOSTerrainDataDestroy"), SuppressUnmanagedCodeSecurity] | ||
1038 | public static extern void GeomOSTerrainDataDestroy(IntPtr d); | ||
1039 | |||
1040 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomOSTerrainDataSetBounds"), SuppressUnmanagedCodeSecurity] | ||
1041 | public static extern void GeomOSTerrainDataSetBounds(IntPtr d, dReal minHeight, dReal maxHeight); | ||
1042 | |||
1043 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomOSTerrainGetHeightfieldData"), SuppressUnmanagedCodeSecurity] | ||
1044 | public static extern IntPtr GeomOSTerrainGetHeightfieldData(IntPtr g); | ||
1045 | |||
1046 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomOSTerrainSetHeightfieldData"), SuppressUnmanagedCodeSecurity] | ||
1047 | public static extern void GeomOSTerrainSetHeightfieldData(IntPtr g, IntPtr d); | ||
1048 | |||
1049 | |||
1050 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomIsEnabled"), SuppressUnmanagedCodeSecurity] | ||
1051 | public static extern bool GeomIsEnabled(IntPtr geom); | ||
1052 | |||
1053 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomIsOffset"), SuppressUnmanagedCodeSecurity] | ||
1054 | public static extern bool GeomIsOffset(IntPtr geom); | ||
1055 | |||
1056 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomIsSpace"), SuppressUnmanagedCodeSecurity] | ||
1057 | public static extern bool GeomIsSpace(IntPtr geom); | ||
1058 | |||
1059 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomPlaneGetParams"), SuppressUnmanagedCodeSecurity] | ||
1060 | public static extern void GeomPlaneGetParams(IntPtr geom, ref Vector4 result); | ||
1061 | |||
1062 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomPlaneGetParams"), SuppressUnmanagedCodeSecurity] | ||
1063 | public static extern void GeomPlaneGetParams(IntPtr geom, ref dReal A); | ||
1064 | |||
1065 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomPlanePointDepth"), SuppressUnmanagedCodeSecurity] | ||
1066 | public static extern dReal GeomPlanePointDepth(IntPtr geom, dReal x, dReal y, dReal z); | ||
1067 | |||
1068 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomPlaneSetParams"), SuppressUnmanagedCodeSecurity] | ||
1069 | public static extern void GeomPlaneSetParams(IntPtr plane, dReal a, dReal b, dReal c, dReal d); | ||
1070 | |||
1071 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRayGet"), SuppressUnmanagedCodeSecurity] | ||
1072 | public static extern void GeomRayGet(IntPtr ray, ref Vector3 start, ref Vector3 dir); | ||
1073 | |||
1074 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRayGet"), SuppressUnmanagedCodeSecurity] | ||
1075 | public static extern void GeomRayGet(IntPtr ray, ref dReal startX, ref dReal dirX); | ||
1076 | |||
1077 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRayGetClosestHit"), SuppressUnmanagedCodeSecurity] | ||
1078 | public static extern int GeomRayGetClosestHit(IntPtr ray); | ||
1079 | |||
1080 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRayGetLength"), SuppressUnmanagedCodeSecurity] | ||
1081 | public static extern dReal GeomRayGetLength(IntPtr ray); | ||
1082 | |||
1083 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRayGetParams"), SuppressUnmanagedCodeSecurity] | ||
1084 | public static extern dReal GeomRayGetParams(IntPtr g, out int firstContact, out int backfaceCull); | ||
1085 | |||
1086 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRaySet"), SuppressUnmanagedCodeSecurity] | ||
1087 | public static extern void GeomRaySet(IntPtr ray, dReal px, dReal py, dReal pz, dReal dx, dReal dy, dReal dz); | ||
1088 | |||
1089 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRaySetClosestHit"), SuppressUnmanagedCodeSecurity] | ||
1090 | public static extern void GeomRaySetClosestHit(IntPtr ray, int closestHit); | ||
1091 | |||
1092 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRaySetLength"), SuppressUnmanagedCodeSecurity] | ||
1093 | public static extern void GeomRaySetLength(IntPtr ray, dReal length); | ||
1094 | |||
1095 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomRaySetParams"), SuppressUnmanagedCodeSecurity] | ||
1096 | public static extern void GeomRaySetParams(IntPtr ray, int firstContact, int backfaceCull); | ||
1097 | |||
1098 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetBody"), SuppressUnmanagedCodeSecurity] | ||
1099 | public static extern void GeomSetBody(IntPtr geom, IntPtr body); | ||
1100 | |||
1101 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetCategoryBits"), SuppressUnmanagedCodeSecurity] | ||
1102 | public static extern void GeomSetCategoryBits(IntPtr geom, uint bits); | ||
1103 | |||
1104 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetCollideBits"), SuppressUnmanagedCodeSecurity] | ||
1105 | public static extern void GeomSetCollideBits(IntPtr geom, uint bits); | ||
1106 | |||
1107 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetConvex"), SuppressUnmanagedCodeSecurity] | ||
1108 | public static extern IntPtr GeomSetConvex(IntPtr geom, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons); | ||
1109 | |||
1110 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetData"), SuppressUnmanagedCodeSecurity] | ||
1111 | public static extern void GeomSetData(IntPtr geom, IntPtr data); | ||
1112 | |||
1113 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetPosition"), SuppressUnmanagedCodeSecurity] | ||
1114 | public static extern void GeomSetOffsetPosition(IntPtr geom, dReal x, dReal y, dReal z); | ||
1115 | |||
1116 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
1117 | public static extern void GeomSetOffsetQuaternion(IntPtr geom, ref Quaternion Q); | ||
1118 | |||
1119 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
1120 | public static extern void GeomSetOffsetQuaternion(IntPtr geom, ref dReal X); | ||
1121 | |||
1122 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetRotation"), SuppressUnmanagedCodeSecurity] | ||
1123 | public static extern void GeomSetOffsetRotation(IntPtr geom, ref Matrix3 R); | ||
1124 | |||
1125 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetRotation"), SuppressUnmanagedCodeSecurity] | ||
1126 | public static extern void GeomSetOffsetRotation(IntPtr geom, ref dReal M00); | ||
1127 | |||
1128 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetWorldPosition"), SuppressUnmanagedCodeSecurity] | ||
1129 | public static extern void GeomSetOffsetWorldPosition(IntPtr geom, dReal x, dReal y, dReal z); | ||
1130 | |||
1131 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetWorldQuaternion"), SuppressUnmanagedCodeSecurity] | ||
1132 | public static extern void GeomSetOffsetWorldQuaternion(IntPtr geom, ref Quaternion Q); | ||
1133 | |||
1134 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetWorldQuaternion"), SuppressUnmanagedCodeSecurity] | ||
1135 | public static extern void GeomSetOffsetWorldQuaternion(IntPtr geom, ref dReal X); | ||
1136 | |||
1137 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetWorldRotation"), SuppressUnmanagedCodeSecurity] | ||
1138 | public static extern void GeomSetOffsetWorldRotation(IntPtr geom, ref Matrix3 R); | ||
1139 | |||
1140 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetOffsetWorldRotation"), SuppressUnmanagedCodeSecurity] | ||
1141 | public static extern void GeomSetOffsetWorldRotation(IntPtr geom, ref dReal M00); | ||
1142 | |||
1143 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetPosition"), SuppressUnmanagedCodeSecurity] | ||
1144 | public static extern void GeomSetPosition(IntPtr geom, dReal x, dReal y, dReal z); | ||
1145 | |||
1146 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
1147 | public static extern void GeomSetQuaternion(IntPtr geom, ref Quaternion quat); | ||
1148 | |||
1149 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetQuaternion"), SuppressUnmanagedCodeSecurity] | ||
1150 | public static extern void GeomSetQuaternion(IntPtr geom, ref dReal w); | ||
1151 | |||
1152 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetRotation"), SuppressUnmanagedCodeSecurity] | ||
1153 | public static extern void GeomSetRotation(IntPtr geom, ref Matrix3 R); | ||
1154 | |||
1155 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetRotation"), SuppressUnmanagedCodeSecurity] | ||
1156 | public static extern void GeomSetRotation(IntPtr geom, ref dReal M00); | ||
1157 | |||
1158 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSphereGetRadius"), SuppressUnmanagedCodeSecurity] | ||
1159 | public static extern dReal GeomSphereGetRadius(IntPtr geom); | ||
1160 | |||
1161 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSpherePointDepth"), SuppressUnmanagedCodeSecurity] | ||
1162 | public static extern dReal GeomSpherePointDepth(IntPtr geom, dReal x, dReal y, dReal z); | ||
1163 | |||
1164 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSphereSetRadius"), SuppressUnmanagedCodeSecurity] | ||
1165 | public static extern void GeomSphereSetRadius(IntPtr geom, dReal radius); | ||
1166 | |||
1167 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTransformGetCleanup"), SuppressUnmanagedCodeSecurity] | ||
1168 | public static extern int GeomTransformGetCleanup(IntPtr geom); | ||
1169 | |||
1170 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTransformGetGeom"), SuppressUnmanagedCodeSecurity] | ||
1171 | public static extern IntPtr GeomTransformGetGeom(IntPtr geom); | ||
1172 | |||
1173 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTransformGetInfo"), SuppressUnmanagedCodeSecurity] | ||
1174 | public static extern int GeomTransformGetInfo(IntPtr geom); | ||
1175 | |||
1176 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTransformSetCleanup"), SuppressUnmanagedCodeSecurity] | ||
1177 | public static extern void GeomTransformSetCleanup(IntPtr geom, int mode); | ||
1178 | |||
1179 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTransformSetGeom"), SuppressUnmanagedCodeSecurity] | ||
1180 | public static extern void GeomTransformSetGeom(IntPtr geom, IntPtr obj); | ||
1181 | |||
1182 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTransformSetInfo"), SuppressUnmanagedCodeSecurity] | ||
1183 | public static extern void GeomTransformSetInfo(IntPtr geom, int info); | ||
1184 | |||
1185 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildDouble"), SuppressUnmanagedCodeSecurity] | ||
1186 | public static extern void GeomTriMeshDataBuildDouble(IntPtr d, | ||
1187 | double[] vertices, int vertexStride, int vertexCount, | ||
1188 | int[] indices, int indexCount, int triStride); | ||
1189 | |||
1190 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildDouble"), SuppressUnmanagedCodeSecurity] | ||
1191 | public static extern void GeomTriMeshDataBuildDouble(IntPtr d, | ||
1192 | IntPtr vertices, int vertexStride, int vertexCount, | ||
1193 | IntPtr indices, int indexCount, int triStride); | ||
1194 | |||
1195 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildDouble1"), SuppressUnmanagedCodeSecurity] | ||
1196 | public static extern void GeomTriMeshDataBuildDouble1(IntPtr d, | ||
1197 | double[] vertices, int vertexStride, int vertexCount, | ||
1198 | int[] indices, int indexCount, int triStride, | ||
1199 | double[] normals); | ||
1200 | |||
1201 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildDouble1"), SuppressUnmanagedCodeSecurity] | ||
1202 | public static extern void GeomTriMeshDataBuildDouble(IntPtr d, | ||
1203 | IntPtr vertices, int vertexStride, int vertexCount, | ||
1204 | IntPtr indices, int indexCount, int triStride, | ||
1205 | IntPtr normals); | ||
1206 | |||
1207 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildSimple"), SuppressUnmanagedCodeSecurity] | ||
1208 | public static extern void GeomTriMeshDataBuildSingle(IntPtr d, | ||
1209 | dReal[] vertices, int vertexStride, int vertexCount, | ||
1210 | int[] indices, int indexCount, int triStride); | ||
1211 | |||
1212 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildSimple"), SuppressUnmanagedCodeSecurity] | ||
1213 | public static extern void GeomTriMeshDataBuildSingle(IntPtr d, | ||
1214 | IntPtr vertices, int vertexStride, int vertexCount, | ||
1215 | IntPtr indices, int indexCount, int triStride); | ||
1216 | |||
1217 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildSimple1"), SuppressUnmanagedCodeSecurity] | ||
1218 | public static extern void GeomTriMeshDataBuildSingle1(IntPtr d, | ||
1219 | dReal[] vertices, int vertexStride, int vertexCount, | ||
1220 | int[] indices, int indexCount, int triStride, | ||
1221 | dReal[] normals); | ||
1222 | |||
1223 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildSimple1"), SuppressUnmanagedCodeSecurity] | ||
1224 | public static extern void GeomTriMeshDataBuildSingle1(IntPtr d, | ||
1225 | IntPtr vertices, int vertexStride, int vertexCount, | ||
1226 | IntPtr indices, int indexCount, int triStride, | ||
1227 | IntPtr normals); | ||
1228 | |||
1229 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildSingle"), SuppressUnmanagedCodeSecurity] | ||
1230 | public static extern void GeomTriMeshDataBuildSimple(IntPtr d, | ||
1231 | float[] vertices, int vertexStride, int vertexCount, | ||
1232 | int[] indices, int indexCount, int triStride); | ||
1233 | |||
1234 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildSingle"), SuppressUnmanagedCodeSecurity] | ||
1235 | public static extern void GeomTriMeshDataBuildSimple(IntPtr d, | ||
1236 | IntPtr vertices, int vertexStride, int vertexCount, | ||
1237 | IntPtr indices, int indexCount, int triStride); | ||
1238 | |||
1239 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildSingle1"), SuppressUnmanagedCodeSecurity] | ||
1240 | public static extern void GeomTriMeshDataBuildSimple1(IntPtr d, | ||
1241 | float[] vertices, int vertexStride, int vertexCount, | ||
1242 | int[] indices, int indexCount, int triStride, | ||
1243 | float[] normals); | ||
1244 | |||
1245 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataBuildSingle1"), SuppressUnmanagedCodeSecurity] | ||
1246 | public static extern void GeomTriMeshDataBuildSimple1(IntPtr d, | ||
1247 | IntPtr vertices, int vertexStride, int vertexCount, | ||
1248 | IntPtr indices, int indexCount, int triStride, | ||
1249 | IntPtr normals); | ||
1250 | |||
1251 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshClearTCCache"), SuppressUnmanagedCodeSecurity] | ||
1252 | public static extern void GeomTriMeshClearTCCache(IntPtr g); | ||
1253 | |||
1254 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataCreate"), SuppressUnmanagedCodeSecurity] | ||
1255 | public static extern IntPtr GeomTriMeshDataCreate(); | ||
1256 | |||
1257 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataDestroy"), SuppressUnmanagedCodeSecurity] | ||
1258 | public static extern void GeomTriMeshDataDestroy(IntPtr d); | ||
1259 | |||
1260 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataGet"), SuppressUnmanagedCodeSecurity] | ||
1261 | public static extern IntPtr GeomTriMeshDataGet(IntPtr d, int data_id); | ||
1262 | |||
1263 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataPreprocess"), SuppressUnmanagedCodeSecurity] | ||
1264 | public static extern void GeomTriMeshDataPreprocess(IntPtr d); | ||
1265 | |||
1266 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataSet"), SuppressUnmanagedCodeSecurity] | ||
1267 | public static extern void GeomTriMeshDataSet(IntPtr d, int data_id, IntPtr in_data); | ||
1268 | |||
1269 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshDataUpdate"), SuppressUnmanagedCodeSecurity] | ||
1270 | public static extern void GeomTriMeshDataUpdate(IntPtr d); | ||
1271 | |||
1272 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshEnableTC"), SuppressUnmanagedCodeSecurity] | ||
1273 | public static extern void GeomTriMeshEnableTC(IntPtr g, int geomClass, bool enable); | ||
1274 | |||
1275 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetArrayCallback"), SuppressUnmanagedCodeSecurity] | ||
1276 | public static extern TriArrayCallback GeomTriMeshGetArrayCallback(IntPtr g); | ||
1277 | |||
1278 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetCallback"), SuppressUnmanagedCodeSecurity] | ||
1279 | public static extern TriCallback GeomTriMeshGetCallback(IntPtr g); | ||
1280 | |||
1281 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetData"), SuppressUnmanagedCodeSecurity] | ||
1282 | public static extern IntPtr GeomTriMeshGetData(IntPtr g); | ||
1283 | |||
1284 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetLastTransform"), SuppressUnmanagedCodeSecurity] | ||
1285 | public extern unsafe static Matrix4* GeomTriMeshGetLastTransformUnsafe(IntPtr geom); | ||
1286 | public static Matrix4 GeomTriMeshGetLastTransform(IntPtr geom) | ||
1287 | { | ||
1288 | unsafe { return *(GeomTriMeshGetLastTransformUnsafe(geom)); } | ||
1289 | } | ||
1290 | |||
1291 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetPoint"), SuppressUnmanagedCodeSecurity] | ||
1292 | public extern static void GeomTriMeshGetPoint(IntPtr g, int index, dReal u, dReal v, ref Vector3 outVec); | ||
1293 | |||
1294 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetRayCallback"), SuppressUnmanagedCodeSecurity] | ||
1295 | public static extern TriRayCallback GeomTriMeshGetRayCallback(IntPtr g); | ||
1296 | |||
1297 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetTriangle"), SuppressUnmanagedCodeSecurity] | ||
1298 | public extern static void GeomTriMeshGetTriangle(IntPtr g, int index, ref Vector3 v0, ref Vector3 v1, ref Vector3 v2); | ||
1299 | |||
1300 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetTriangleCount"), SuppressUnmanagedCodeSecurity] | ||
1301 | public extern static int GeomTriMeshGetTriangleCount(IntPtr g); | ||
1302 | |||
1303 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshGetTriMeshDataID"), SuppressUnmanagedCodeSecurity] | ||
1304 | public static extern IntPtr GeomTriMeshGetTriMeshDataID(IntPtr g); | ||
1305 | |||
1306 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshIsTCEnabled"), SuppressUnmanagedCodeSecurity] | ||
1307 | public static extern bool GeomTriMeshIsTCEnabled(IntPtr g, int geomClass); | ||
1308 | |||
1309 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshSetArrayCallback"), SuppressUnmanagedCodeSecurity] | ||
1310 | public static extern void GeomTriMeshSetArrayCallback(IntPtr g, TriArrayCallback arrayCallback); | ||
1311 | |||
1312 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshSetCallback"), SuppressUnmanagedCodeSecurity] | ||
1313 | public static extern void GeomTriMeshSetCallback(IntPtr g, TriCallback callback); | ||
1314 | |||
1315 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshSetData"), SuppressUnmanagedCodeSecurity] | ||
1316 | public static extern void GeomTriMeshSetData(IntPtr g, IntPtr data); | ||
1317 | |||
1318 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshSetLastTransform"), SuppressUnmanagedCodeSecurity] | ||
1319 | public static extern void GeomTriMeshSetLastTransform(IntPtr g, ref Matrix4 last_trans); | ||
1320 | |||
1321 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshSetLastTransform"), SuppressUnmanagedCodeSecurity] | ||
1322 | public static extern void GeomTriMeshSetLastTransform(IntPtr g, ref dReal M00); | ||
1323 | |||
1324 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomTriMeshSetRayCallback"), SuppressUnmanagedCodeSecurity] | ||
1325 | public static extern void GeomTriMeshSetRayCallback(IntPtr g, TriRayCallback callback); | ||
1326 | |||
1327 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGetConfiguration"), SuppressUnmanagedCodeSecurity] | ||
1328 | public static extern IntPtr iGetConfiguration(); | ||
1329 | |||
1330 | public static string GetConfiguration() | ||
1331 | { | ||
1332 | IntPtr ptr = iGetConfiguration(); | ||
1333 | string s = Marshal.PtrToStringAnsi(ptr); | ||
1334 | return s; | ||
1335 | } | ||
1336 | |||
1337 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dHashSpaceCreate"), SuppressUnmanagedCodeSecurity] | ||
1338 | public static extern IntPtr HashSpaceCreate(IntPtr space); | ||
1339 | |||
1340 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dHashSpaceGetLevels"), SuppressUnmanagedCodeSecurity] | ||
1341 | public static extern void HashSpaceGetLevels(IntPtr space, out int minlevel, out int maxlevel); | ||
1342 | |||
1343 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dHashSpaceSetLevels"), SuppressUnmanagedCodeSecurity] | ||
1344 | public static extern void HashSpaceSetLevels(IntPtr space, int minlevel, int maxlevel); | ||
1345 | |||
1346 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dInfiniteAABB"), SuppressUnmanagedCodeSecurity] | ||
1347 | public static extern void InfiniteAABB(IntPtr geom, out AABB aabb); | ||
1348 | |||
1349 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dInitODE"), SuppressUnmanagedCodeSecurity] | ||
1350 | public static extern void InitODE(); | ||
1351 | |||
1352 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dInitODE2"), SuppressUnmanagedCodeSecurity] | ||
1353 | public static extern int InitODE2(uint ODEInitFlags); | ||
1354 | |||
1355 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dIsPositiveDefinite"), SuppressUnmanagedCodeSecurity] | ||
1356 | public static extern int IsPositiveDefinite(ref dReal A, int n); | ||
1357 | |||
1358 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dInvertPDMatrix"), SuppressUnmanagedCodeSecurity] | ||
1359 | public static extern int InvertPDMatrix(ref dReal A, out dReal Ainv, int n); | ||
1360 | |||
1361 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointAddAMotorTorques"), SuppressUnmanagedCodeSecurity] | ||
1362 | public static extern void JointAddAMotorTorques(IntPtr joint, dReal torque1, dReal torque2, dReal torque3); | ||
1363 | |||
1364 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointAddHingeTorque"), SuppressUnmanagedCodeSecurity] | ||
1365 | public static extern void JointAddHingeTorque(IntPtr joint, dReal torque); | ||
1366 | |||
1367 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointAddHinge2Torque"), SuppressUnmanagedCodeSecurity] | ||
1368 | public static extern void JointAddHinge2Torques(IntPtr joint, dReal torque1, dReal torque2); | ||
1369 | |||
1370 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointAddPRTorque"), SuppressUnmanagedCodeSecurity] | ||
1371 | public static extern void JointAddPRTorque(IntPtr joint, dReal torque); | ||
1372 | |||
1373 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointAddUniversalTorque"), SuppressUnmanagedCodeSecurity] | ||
1374 | public static extern void JointAddUniversalTorques(IntPtr joint, dReal torque1, dReal torque2); | ||
1375 | |||
1376 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointAddSliderForce"), SuppressUnmanagedCodeSecurity] | ||
1377 | public static extern void JointAddSliderForce(IntPtr joint, dReal force); | ||
1378 | |||
1379 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointAttach"), SuppressUnmanagedCodeSecurity] | ||
1380 | public static extern void JointAttach(IntPtr joint, IntPtr body1, IntPtr body2); | ||
1381 | |||
1382 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateAMotor"), SuppressUnmanagedCodeSecurity] | ||
1383 | public static extern IntPtr JointCreateAMotor(IntPtr world, IntPtr group); | ||
1384 | |||
1385 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateBall"), SuppressUnmanagedCodeSecurity] | ||
1386 | public static extern IntPtr JointCreateBall(IntPtr world, IntPtr group); | ||
1387 | |||
1388 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateContact"), SuppressUnmanagedCodeSecurity] | ||
1389 | public static extern IntPtr JointCreateContact(IntPtr world, IntPtr group, ref Contact contact); | ||
1390 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateContact"), SuppressUnmanagedCodeSecurity] | ||
1391 | public static extern IntPtr JointCreateContactPtr(IntPtr world, IntPtr group, IntPtr contact); | ||
1392 | |||
1393 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateFixed"), SuppressUnmanagedCodeSecurity] | ||
1394 | public static extern IntPtr JointCreateFixed(IntPtr world, IntPtr group); | ||
1395 | |||
1396 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateHinge"), SuppressUnmanagedCodeSecurity] | ||
1397 | public static extern IntPtr JointCreateHinge(IntPtr world, IntPtr group); | ||
1398 | |||
1399 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateHinge2"), SuppressUnmanagedCodeSecurity] | ||
1400 | public static extern IntPtr JointCreateHinge2(IntPtr world, IntPtr group); | ||
1401 | |||
1402 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateLMotor"), SuppressUnmanagedCodeSecurity] | ||
1403 | public static extern IntPtr JointCreateLMotor(IntPtr world, IntPtr group); | ||
1404 | |||
1405 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateNull"), SuppressUnmanagedCodeSecurity] | ||
1406 | public static extern IntPtr JointCreateNull(IntPtr world, IntPtr group); | ||
1407 | |||
1408 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreatePR"), SuppressUnmanagedCodeSecurity] | ||
1409 | public static extern IntPtr JointCreatePR(IntPtr world, IntPtr group); | ||
1410 | |||
1411 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreatePlane2D"), SuppressUnmanagedCodeSecurity] | ||
1412 | public static extern IntPtr JointCreatePlane2D(IntPtr world, IntPtr group); | ||
1413 | |||
1414 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateSlider"), SuppressUnmanagedCodeSecurity] | ||
1415 | public static extern IntPtr JointCreateSlider(IntPtr world, IntPtr group); | ||
1416 | |||
1417 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointCreateUniversal"), SuppressUnmanagedCodeSecurity] | ||
1418 | public static extern IntPtr JointCreateUniversal(IntPtr world, IntPtr group); | ||
1419 | |||
1420 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointDestroy"), SuppressUnmanagedCodeSecurity] | ||
1421 | public static extern void JointDestroy(IntPtr j); | ||
1422 | |||
1423 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetAMotorAngle"), SuppressUnmanagedCodeSecurity] | ||
1424 | public static extern dReal JointGetAMotorAngle(IntPtr j, int anum); | ||
1425 | |||
1426 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetAMotorAngleRate"), SuppressUnmanagedCodeSecurity] | ||
1427 | public static extern dReal JointGetAMotorAngleRate(IntPtr j, int anum); | ||
1428 | |||
1429 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetAMotorAxis"), SuppressUnmanagedCodeSecurity] | ||
1430 | public static extern void JointGetAMotorAxis(IntPtr j, int anum, out Vector3 result); | ||
1431 | |||
1432 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetAMotorAxisRel"), SuppressUnmanagedCodeSecurity] | ||
1433 | public static extern int JointGetAMotorAxisRel(IntPtr j, int anum); | ||
1434 | |||
1435 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetAMotorMode"), SuppressUnmanagedCodeSecurity] | ||
1436 | public static extern int JointGetAMotorMode(IntPtr j); | ||
1437 | |||
1438 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetAMotorNumAxes"), SuppressUnmanagedCodeSecurity] | ||
1439 | public static extern int JointGetAMotorNumAxes(IntPtr j); | ||
1440 | |||
1441 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetAMotorParam"), SuppressUnmanagedCodeSecurity] | ||
1442 | public static extern dReal JointGetAMotorParam(IntPtr j, int parameter); | ||
1443 | |||
1444 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetBallAnchor"), SuppressUnmanagedCodeSecurity] | ||
1445 | public static extern void JointGetBallAnchor(IntPtr j, out Vector3 result); | ||
1446 | |||
1447 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetBallAnchor2"), SuppressUnmanagedCodeSecurity] | ||
1448 | public static extern void JointGetBallAnchor2(IntPtr j, out Vector3 result); | ||
1449 | |||
1450 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetBody"), SuppressUnmanagedCodeSecurity] | ||
1451 | public static extern IntPtr JointGetBody(IntPtr j); | ||
1452 | |||
1453 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetData"), SuppressUnmanagedCodeSecurity] | ||
1454 | public static extern IntPtr JointGetData(IntPtr j); | ||
1455 | |||
1456 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetFeedback"), SuppressUnmanagedCodeSecurity] | ||
1457 | public extern unsafe static JointFeedback* JointGetFeedbackUnsafe(IntPtr j); | ||
1458 | public static JointFeedback JointGetFeedback(IntPtr j) | ||
1459 | { | ||
1460 | unsafe { return *(JointGetFeedbackUnsafe(j)); } | ||
1461 | } | ||
1462 | |||
1463 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHingeAnchor"), SuppressUnmanagedCodeSecurity] | ||
1464 | public static extern void JointGetHingeAnchor(IntPtr j, out Vector3 result); | ||
1465 | |||
1466 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHingeAngle"), SuppressUnmanagedCodeSecurity] | ||
1467 | public static extern dReal JointGetHingeAngle(IntPtr j); | ||
1468 | |||
1469 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHingeAngleRate"), SuppressUnmanagedCodeSecurity] | ||
1470 | public static extern dReal JointGetHingeAngleRate(IntPtr j); | ||
1471 | |||
1472 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHingeAxis"), SuppressUnmanagedCodeSecurity] | ||
1473 | public static extern void JointGetHingeAxis(IntPtr j, out Vector3 result); | ||
1474 | |||
1475 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHingeParam"), SuppressUnmanagedCodeSecurity] | ||
1476 | public static extern dReal JointGetHingeParam(IntPtr j, int parameter); | ||
1477 | |||
1478 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHinge2Angle1"), SuppressUnmanagedCodeSecurity] | ||
1479 | public static extern dReal JointGetHinge2Angle1(IntPtr j); | ||
1480 | |||
1481 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHinge2Angle1Rate"), SuppressUnmanagedCodeSecurity] | ||
1482 | public static extern dReal JointGetHinge2Angle1Rate(IntPtr j); | ||
1483 | |||
1484 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHinge2Angle2Rate"), SuppressUnmanagedCodeSecurity] | ||
1485 | public static extern dReal JointGetHinge2Angle2Rate(IntPtr j); | ||
1486 | |||
1487 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHingeAnchor2"), SuppressUnmanagedCodeSecurity] | ||
1488 | public static extern void JointGetHingeAnchor2(IntPtr j, out Vector3 result); | ||
1489 | |||
1490 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHinge2Anchor"), SuppressUnmanagedCodeSecurity] | ||
1491 | public static extern void JointGetHinge2Anchor(IntPtr j, out Vector3 result); | ||
1492 | |||
1493 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHinge2Anchor2"), SuppressUnmanagedCodeSecurity] | ||
1494 | public static extern void JointGetHinge2Anchor2(IntPtr j, out Vector3 result); | ||
1495 | |||
1496 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHinge2Axis1"), SuppressUnmanagedCodeSecurity] | ||
1497 | public static extern void JointGetHinge2Axis1(IntPtr j, out Vector3 result); | ||
1498 | |||
1499 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHinge2Axis2"), SuppressUnmanagedCodeSecurity] | ||
1500 | public static extern void JointGetHinge2Axis2(IntPtr j, out Vector3 result); | ||
1501 | |||
1502 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetHinge2Param"), SuppressUnmanagedCodeSecurity] | ||
1503 | public static extern dReal JointGetHinge2Param(IntPtr j, int parameter); | ||
1504 | |||
1505 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetLMotorAxis"), SuppressUnmanagedCodeSecurity] | ||
1506 | public static extern void JointGetLMotorAxis(IntPtr j, int anum, out Vector3 result); | ||
1507 | |||
1508 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetLMotorNumAxes"), SuppressUnmanagedCodeSecurity] | ||
1509 | public static extern int JointGetLMotorNumAxes(IntPtr j); | ||
1510 | |||
1511 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetLMotorParam"), SuppressUnmanagedCodeSecurity] | ||
1512 | public static extern dReal JointGetLMotorParam(IntPtr j, int parameter); | ||
1513 | |||
1514 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetPRAnchor"), SuppressUnmanagedCodeSecurity] | ||
1515 | public static extern void JointGetPRAnchor(IntPtr j, out Vector3 result); | ||
1516 | |||
1517 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetPRAxis1"), SuppressUnmanagedCodeSecurity] | ||
1518 | public static extern void JointGetPRAxis1(IntPtr j, out Vector3 result); | ||
1519 | |||
1520 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetPRAxis2"), SuppressUnmanagedCodeSecurity] | ||
1521 | public static extern void JointGetPRAxis2(IntPtr j, out Vector3 result); | ||
1522 | |||
1523 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetPRParam"), SuppressUnmanagedCodeSecurity] | ||
1524 | public static extern dReal JointGetPRParam(IntPtr j, int parameter); | ||
1525 | |||
1526 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetPRPosition"), SuppressUnmanagedCodeSecurity] | ||
1527 | public static extern dReal JointGetPRPosition(IntPtr j); | ||
1528 | |||
1529 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetPRPositionRate"), SuppressUnmanagedCodeSecurity] | ||
1530 | public static extern dReal JointGetPRPositionRate(IntPtr j); | ||
1531 | |||
1532 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetSliderAxis"), SuppressUnmanagedCodeSecurity] | ||
1533 | public static extern void JointGetSliderAxis(IntPtr j, out Vector3 result); | ||
1534 | |||
1535 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetSliderParam"), SuppressUnmanagedCodeSecurity] | ||
1536 | public static extern dReal JointGetSliderParam(IntPtr j, int parameter); | ||
1537 | |||
1538 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetSliderPosition"), SuppressUnmanagedCodeSecurity] | ||
1539 | public static extern dReal JointGetSliderPosition(IntPtr j); | ||
1540 | |||
1541 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetSliderPositionRate"), SuppressUnmanagedCodeSecurity] | ||
1542 | public static extern dReal JointGetSliderPositionRate(IntPtr j); | ||
1543 | |||
1544 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetType"), SuppressUnmanagedCodeSecurity] | ||
1545 | public static extern JointType JointGetType(IntPtr j); | ||
1546 | |||
1547 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAnchor"), SuppressUnmanagedCodeSecurity] | ||
1548 | public static extern void JointGetUniversalAnchor(IntPtr j, out Vector3 result); | ||
1549 | |||
1550 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAnchor2"), SuppressUnmanagedCodeSecurity] | ||
1551 | public static extern void JointGetUniversalAnchor2(IntPtr j, out Vector3 result); | ||
1552 | |||
1553 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAngle1"), SuppressUnmanagedCodeSecurity] | ||
1554 | public static extern dReal JointGetUniversalAngle1(IntPtr j); | ||
1555 | |||
1556 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAngle1Rate"), SuppressUnmanagedCodeSecurity] | ||
1557 | public static extern dReal JointGetUniversalAngle1Rate(IntPtr j); | ||
1558 | |||
1559 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAngle2"), SuppressUnmanagedCodeSecurity] | ||
1560 | public static extern dReal JointGetUniversalAngle2(IntPtr j); | ||
1561 | |||
1562 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAngle2Rate"), SuppressUnmanagedCodeSecurity] | ||
1563 | public static extern dReal JointGetUniversalAngle2Rate(IntPtr j); | ||
1564 | |||
1565 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAngles"), SuppressUnmanagedCodeSecurity] | ||
1566 | public static extern void JointGetUniversalAngles(IntPtr j, out dReal angle1, out dReal angle2); | ||
1567 | |||
1568 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAxis1"), SuppressUnmanagedCodeSecurity] | ||
1569 | public static extern void JointGetUniversalAxis1(IntPtr j, out Vector3 result); | ||
1570 | |||
1571 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalAxis2"), SuppressUnmanagedCodeSecurity] | ||
1572 | public static extern void JointGetUniversalAxis2(IntPtr j, out Vector3 result); | ||
1573 | |||
1574 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGetUniversalParam"), SuppressUnmanagedCodeSecurity] | ||
1575 | public static extern dReal JointGetUniversalParam(IntPtr j, int parameter); | ||
1576 | |||
1577 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGroupCreate"), SuppressUnmanagedCodeSecurity] | ||
1578 | public static extern IntPtr JointGroupCreate(int max_size); | ||
1579 | |||
1580 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGroupDestroy"), SuppressUnmanagedCodeSecurity] | ||
1581 | public static extern void JointGroupDestroy(IntPtr group); | ||
1582 | |||
1583 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointGroupEmpty"), SuppressUnmanagedCodeSecurity] | ||
1584 | public static extern void JointGroupEmpty(IntPtr group); | ||
1585 | |||
1586 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetAMotorAngle"), SuppressUnmanagedCodeSecurity] | ||
1587 | public static extern void JointSetAMotorAngle(IntPtr j, int anum, dReal angle); | ||
1588 | |||
1589 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetAMotorAxis"), SuppressUnmanagedCodeSecurity] | ||
1590 | public static extern void JointSetAMotorAxis(IntPtr j, int anum, int rel, dReal x, dReal y, dReal z); | ||
1591 | |||
1592 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetAMotorMode"), SuppressUnmanagedCodeSecurity] | ||
1593 | public static extern void JointSetAMotorMode(IntPtr j, int mode); | ||
1594 | |||
1595 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetAMotorNumAxes"), SuppressUnmanagedCodeSecurity] | ||
1596 | public static extern void JointSetAMotorNumAxes(IntPtr group, int num); | ||
1597 | |||
1598 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetAMotorParam"), SuppressUnmanagedCodeSecurity] | ||
1599 | public static extern void JointSetAMotorParam(IntPtr group, int parameter, dReal value); | ||
1600 | |||
1601 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetBallAnchor"), SuppressUnmanagedCodeSecurity] | ||
1602 | public static extern void JointSetBallAnchor(IntPtr j, dReal x, dReal y, dReal z); | ||
1603 | |||
1604 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetBallAnchor2"), SuppressUnmanagedCodeSecurity] | ||
1605 | public static extern void JointSetBallAnchor2(IntPtr j, dReal x, dReal y, dReal z); | ||
1606 | |||
1607 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetData"), SuppressUnmanagedCodeSecurity] | ||
1608 | public static extern void JointSetData(IntPtr j, IntPtr data); | ||
1609 | |||
1610 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetFeedback"), SuppressUnmanagedCodeSecurity] | ||
1611 | public static extern void JointSetFeedback(IntPtr j, out JointFeedback feedback); | ||
1612 | |||
1613 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetFixed"), SuppressUnmanagedCodeSecurity] | ||
1614 | public static extern void JointSetFixed(IntPtr j); | ||
1615 | |||
1616 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetHingeAnchor"), SuppressUnmanagedCodeSecurity] | ||
1617 | public static extern void JointSetHingeAnchor(IntPtr j, dReal x, dReal y, dReal z); | ||
1618 | |||
1619 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetHingeAnchorDelta"), SuppressUnmanagedCodeSecurity] | ||
1620 | public static extern void JointSetHingeAnchorDelta(IntPtr j, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); | ||
1621 | |||
1622 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetHingeAxis"), SuppressUnmanagedCodeSecurity] | ||
1623 | public static extern void JointSetHingeAxis(IntPtr j, dReal x, dReal y, dReal z); | ||
1624 | |||
1625 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetHingeParam"), SuppressUnmanagedCodeSecurity] | ||
1626 | public static extern void JointSetHingeParam(IntPtr j, int parameter, dReal value); | ||
1627 | |||
1628 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetHinge2Anchor"), SuppressUnmanagedCodeSecurity] | ||
1629 | public static extern void JointSetHinge2Anchor(IntPtr j, dReal x, dReal y, dReal z); | ||
1630 | |||
1631 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetHinge2Axis1"), SuppressUnmanagedCodeSecurity] | ||
1632 | public static extern void JointSetHinge2Axis1(IntPtr j, dReal x, dReal y, dReal z); | ||
1633 | |||
1634 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetHinge2Axis2"), SuppressUnmanagedCodeSecurity] | ||
1635 | public static extern void JointSetHinge2Axis2(IntPtr j, dReal x, dReal y, dReal z); | ||
1636 | |||
1637 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetHinge2Param"), SuppressUnmanagedCodeSecurity] | ||
1638 | public static extern void JointSetHinge2Param(IntPtr j, int parameter, dReal value); | ||
1639 | |||
1640 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetLMotorAxis"), SuppressUnmanagedCodeSecurity] | ||
1641 | public static extern void JointSetLMotorAxis(IntPtr j, int anum, int rel, dReal x, dReal y, dReal z); | ||
1642 | |||
1643 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetLMotorNumAxes"), SuppressUnmanagedCodeSecurity] | ||
1644 | public static extern void JointSetLMotorNumAxes(IntPtr j, int num); | ||
1645 | |||
1646 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetLMotorParam"), SuppressUnmanagedCodeSecurity] | ||
1647 | public static extern void JointSetLMotorParam(IntPtr j, int parameter, dReal value); | ||
1648 | |||
1649 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetPlane2DAngleParam"), SuppressUnmanagedCodeSecurity] | ||
1650 | public static extern void JointSetPlane2DAngleParam(IntPtr j, int parameter, dReal value); | ||
1651 | |||
1652 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetPlane2DXParam"), SuppressUnmanagedCodeSecurity] | ||
1653 | public static extern void JointSetPlane2DXParam(IntPtr j, int parameter, dReal value); | ||
1654 | |||
1655 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetPlane2DYParam"), SuppressUnmanagedCodeSecurity] | ||
1656 | public static extern void JointSetPlane2DYParam(IntPtr j, int parameter, dReal value); | ||
1657 | |||
1658 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetPRAnchor"), SuppressUnmanagedCodeSecurity] | ||
1659 | public static extern void JointSetPRAnchor(IntPtr j, dReal x, dReal y, dReal z); | ||
1660 | |||
1661 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetPRAxis1"), SuppressUnmanagedCodeSecurity] | ||
1662 | public static extern void JointSetPRAxis1(IntPtr j, dReal x, dReal y, dReal z); | ||
1663 | |||
1664 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetPRAxis2"), SuppressUnmanagedCodeSecurity] | ||
1665 | public static extern void JointSetPRAxis2(IntPtr j, dReal x, dReal y, dReal z); | ||
1666 | |||
1667 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetPRParam"), SuppressUnmanagedCodeSecurity] | ||
1668 | public static extern void JointSetPRParam(IntPtr j, int parameter, dReal value); | ||
1669 | |||
1670 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetSliderAxis"), SuppressUnmanagedCodeSecurity] | ||
1671 | public static extern void JointSetSliderAxis(IntPtr j, dReal x, dReal y, dReal z); | ||
1672 | |||
1673 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetSliderAxisDelta"), SuppressUnmanagedCodeSecurity] | ||
1674 | public static extern void JointSetSliderAxisDelta(IntPtr j, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); | ||
1675 | |||
1676 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetSliderParam"), SuppressUnmanagedCodeSecurity] | ||
1677 | public static extern void JointSetSliderParam(IntPtr j, int parameter, dReal value); | ||
1678 | |||
1679 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetUniversalAnchor"), SuppressUnmanagedCodeSecurity] | ||
1680 | public static extern void JointSetUniversalAnchor(IntPtr j, dReal x, dReal y, dReal z); | ||
1681 | |||
1682 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetUniversalAxis1"), SuppressUnmanagedCodeSecurity] | ||
1683 | public static extern void JointSetUniversalAxis1(IntPtr j, dReal x, dReal y, dReal z); | ||
1684 | |||
1685 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetUniversalAxis2"), SuppressUnmanagedCodeSecurity] | ||
1686 | public static extern void JointSetUniversalAxis2(IntPtr j, dReal x, dReal y, dReal z); | ||
1687 | |||
1688 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dJointSetUniversalParam"), SuppressUnmanagedCodeSecurity] | ||
1689 | public static extern void JointSetUniversalParam(IntPtr j, int parameter, dReal value); | ||
1690 | |||
1691 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dLDLTAddTL"), SuppressUnmanagedCodeSecurity] | ||
1692 | public static extern void LDLTAddTL(ref dReal L, ref dReal d, ref dReal a, int n, int nskip); | ||
1693 | |||
1694 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassAdd"), SuppressUnmanagedCodeSecurity] | ||
1695 | public static extern void MassAdd(ref Mass a, ref Mass b); | ||
1696 | |||
1697 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassAdjust"), SuppressUnmanagedCodeSecurity] | ||
1698 | public static extern void MassAdjust(ref Mass m, dReal newmass); | ||
1699 | |||
1700 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassCheck"), SuppressUnmanagedCodeSecurity] | ||
1701 | public static extern bool MassCheck(ref Mass m); | ||
1702 | |||
1703 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassRotate"), SuppressUnmanagedCodeSecurity] | ||
1704 | public static extern void MassRotate(ref Mass mass, ref Matrix3 R); | ||
1705 | |||
1706 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassRotate"), SuppressUnmanagedCodeSecurity] | ||
1707 | public static extern void MassRotate(ref Mass mass, ref dReal M00); | ||
1708 | |||
1709 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetBox"), SuppressUnmanagedCodeSecurity] | ||
1710 | public static extern void MassSetBox(out Mass mass, dReal density, dReal lx, dReal ly, dReal lz); | ||
1711 | |||
1712 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetBoxTotal"), SuppressUnmanagedCodeSecurity] | ||
1713 | public static extern void MassSetBoxTotal(out Mass mass, dReal total_mass, dReal lx, dReal ly, dReal lz); | ||
1714 | |||
1715 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetCapsule"), SuppressUnmanagedCodeSecurity] | ||
1716 | public static extern void MassSetCapsule(out Mass mass, dReal density, int direction, dReal radius, dReal length); | ||
1717 | |||
1718 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetCapsuleTotal"), SuppressUnmanagedCodeSecurity] | ||
1719 | public static extern void MassSetCapsuleTotal(out Mass mass, dReal total_mass, int direction, dReal radius, dReal length); | ||
1720 | |||
1721 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetCylinder"), SuppressUnmanagedCodeSecurity] | ||
1722 | public static extern void MassSetCylinder(out Mass mass, dReal density, int direction, dReal radius, dReal length); | ||
1723 | |||
1724 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetCylinderTotal"), SuppressUnmanagedCodeSecurity] | ||
1725 | public static extern void MassSetCylinderTotal(out Mass mass, dReal total_mass, int direction, dReal radius, dReal length); | ||
1726 | |||
1727 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetParameters"), SuppressUnmanagedCodeSecurity] | ||
1728 | public static extern void MassSetParameters(out Mass mass, dReal themass, | ||
1729 | dReal cgx, dReal cgy, dReal cgz, | ||
1730 | dReal i11, dReal i22, dReal i33, | ||
1731 | dReal i12, dReal i13, dReal i23); | ||
1732 | |||
1733 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetSphere"), SuppressUnmanagedCodeSecurity] | ||
1734 | public static extern void MassSetSphere(out Mass mass, dReal density, dReal radius); | ||
1735 | |||
1736 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetSphereTotal"), SuppressUnmanagedCodeSecurity] | ||
1737 | public static extern void dMassSetSphereTotal(out Mass mass, dReal total_mass, dReal radius); | ||
1738 | |||
1739 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetTrimesh"), SuppressUnmanagedCodeSecurity] | ||
1740 | public static extern void MassSetTrimesh(out Mass mass, dReal density, IntPtr g); | ||
1741 | |||
1742 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassSetZero"), SuppressUnmanagedCodeSecurity] | ||
1743 | public static extern void MassSetZero(out Mass mass); | ||
1744 | |||
1745 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMassTranslate"), SuppressUnmanagedCodeSecurity] | ||
1746 | public static extern void MassTranslate(ref Mass mass, dReal x, dReal y, dReal z); | ||
1747 | |||
1748 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMultiply0"), SuppressUnmanagedCodeSecurity] | ||
1749 | public static extern void Multiply0(out dReal A00, ref dReal B00, ref dReal C00, int p, int q, int r); | ||
1750 | |||
1751 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMultiply0"), SuppressUnmanagedCodeSecurity] | ||
1752 | private static extern void MultiplyiM3V3(out Vector3 vout, ref Matrix3 matrix, ref Vector3 vect,int p, int q, int r); | ||
1753 | public static void MultiplyM3V3(out Vector3 outvector, ref Matrix3 matrix, ref Vector3 invector) | ||
1754 | { | ||
1755 | MultiplyiM3V3(out outvector, ref matrix, ref invector, 3, 3, 1); | ||
1756 | } | ||
1757 | |||
1758 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMultiply1"), SuppressUnmanagedCodeSecurity] | ||
1759 | public static extern void Multiply1(out dReal A00, ref dReal B00, ref dReal C00, int p, int q, int r); | ||
1760 | |||
1761 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dMultiply2"), SuppressUnmanagedCodeSecurity] | ||
1762 | public static extern void Multiply2(out dReal A00, ref dReal B00, ref dReal C00, int p, int q, int r); | ||
1763 | |||
1764 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQFromAxisAndAngle"), SuppressUnmanagedCodeSecurity] | ||
1765 | public static extern void QFromAxisAndAngle(out Quaternion q, dReal ax, dReal ay, dReal az, dReal angle); | ||
1766 | |||
1767 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQfromR"), SuppressUnmanagedCodeSecurity] | ||
1768 | public static extern void QfromR(out Quaternion q, ref Matrix3 R); | ||
1769 | |||
1770 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQMultiply0"), SuppressUnmanagedCodeSecurity] | ||
1771 | public static extern void QMultiply0(out Quaternion qa, ref Quaternion qb, ref Quaternion qc); | ||
1772 | |||
1773 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQMultiply1"), SuppressUnmanagedCodeSecurity] | ||
1774 | public static extern void QMultiply1(out Quaternion qa, ref Quaternion qb, ref Quaternion qc); | ||
1775 | |||
1776 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQMultiply2"), SuppressUnmanagedCodeSecurity] | ||
1777 | public static extern void QMultiply2(out Quaternion qa, ref Quaternion qb, ref Quaternion qc); | ||
1778 | |||
1779 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQMultiply3"), SuppressUnmanagedCodeSecurity] | ||
1780 | public static extern void QMultiply3(out Quaternion qa, ref Quaternion qb, ref Quaternion qc); | ||
1781 | |||
1782 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQSetIdentity"), SuppressUnmanagedCodeSecurity] | ||
1783 | public static extern void QSetIdentity(out Quaternion q); | ||
1784 | |||
1785 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQuadTreeSpaceCreate"), SuppressUnmanagedCodeSecurity] | ||
1786 | public static extern IntPtr QuadTreeSpaceCreate(IntPtr space, ref Vector3 center, ref Vector3 extents, int depth); | ||
1787 | |||
1788 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dQuadTreeSpaceCreate"), SuppressUnmanagedCodeSecurity] | ||
1789 | public static extern IntPtr QuadTreeSpaceCreate(IntPtr space, ref dReal centerX, ref dReal extentsX, int depth); | ||
1790 | |||
1791 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dRandReal"), SuppressUnmanagedCodeSecurity] | ||
1792 | public static extern dReal RandReal(); | ||
1793 | |||
1794 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dRFrom2Axes"), SuppressUnmanagedCodeSecurity] | ||
1795 | public static extern void RFrom2Axes(out Matrix3 R, dReal ax, dReal ay, dReal az, dReal bx, dReal by, dReal bz); | ||
1796 | |||
1797 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dRFromAxisAndAngle"), SuppressUnmanagedCodeSecurity] | ||
1798 | public static extern void RFromAxisAndAngle(out Matrix3 R, dReal x, dReal y, dReal z, dReal angle); | ||
1799 | |||
1800 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dRFromEulerAngles"), SuppressUnmanagedCodeSecurity] | ||
1801 | public static extern void RFromEulerAngles(out Matrix3 R, dReal phi, dReal theta, dReal psi); | ||
1802 | |||
1803 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dRfromQ"), SuppressUnmanagedCodeSecurity] | ||
1804 | public static extern void RfromQ(out Matrix3 R, ref Quaternion q); | ||
1805 | |||
1806 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dRFromZAxis"), SuppressUnmanagedCodeSecurity] | ||
1807 | public static extern void RFromZAxis(out Matrix3 R, dReal ax, dReal ay, dReal az); | ||
1808 | |||
1809 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dRSetIdentity"), SuppressUnmanagedCodeSecurity] | ||
1810 | public static extern void RSetIdentity(out Matrix3 R); | ||
1811 | |||
1812 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSetValue"), SuppressUnmanagedCodeSecurity] | ||
1813 | public static extern void SetValue(out dReal a, int n); | ||
1814 | |||
1815 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSetZero"), SuppressUnmanagedCodeSecurity] | ||
1816 | public static extern void SetZero(out dReal a, int n); | ||
1817 | |||
1818 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSimpleSpaceCreate"), SuppressUnmanagedCodeSecurity] | ||
1819 | public static extern IntPtr SimpleSpaceCreate(IntPtr space); | ||
1820 | |||
1821 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSolveCholesky"), SuppressUnmanagedCodeSecurity] | ||
1822 | public static extern void SolveCholesky(ref dReal L, out dReal b, int n); | ||
1823 | |||
1824 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSolveL1"), SuppressUnmanagedCodeSecurity] | ||
1825 | public static extern void SolveL1(ref dReal L, out dReal b, int n, int nskip); | ||
1826 | |||
1827 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSolveL1T"), SuppressUnmanagedCodeSecurity] | ||
1828 | public static extern void SolveL1T(ref dReal L, out dReal b, int n, int nskip); | ||
1829 | |||
1830 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSolveLDLT"), SuppressUnmanagedCodeSecurity] | ||
1831 | public static extern void SolveLDLT(ref dReal L, ref dReal d, out dReal b, int n, int nskip); | ||
1832 | |||
1833 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceAdd"), SuppressUnmanagedCodeSecurity] | ||
1834 | public static extern void SpaceAdd(IntPtr space, IntPtr geom); | ||
1835 | |||
1836 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceLockQuery"), SuppressUnmanagedCodeSecurity] | ||
1837 | public static extern bool SpaceLockQuery(IntPtr space); | ||
1838 | |||
1839 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceClean"), SuppressUnmanagedCodeSecurity] | ||
1840 | public static extern void SpaceClean(IntPtr space); | ||
1841 | |||
1842 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceCollide"), SuppressUnmanagedCodeSecurity] | ||
1843 | public static extern void SpaceCollide(IntPtr space, IntPtr data, NearCallback callback); | ||
1844 | |||
1845 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceCollide2"), SuppressUnmanagedCodeSecurity] | ||
1846 | public static extern void SpaceCollide2(IntPtr space1, IntPtr space2, IntPtr data, NearCallback callback); | ||
1847 | |||
1848 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceDestroy"), SuppressUnmanagedCodeSecurity] | ||
1849 | public static extern void SpaceDestroy(IntPtr space); | ||
1850 | |||
1851 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceGetCleanup"), SuppressUnmanagedCodeSecurity] | ||
1852 | public static extern bool SpaceGetCleanup(IntPtr space); | ||
1853 | |||
1854 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceGetNumGeoms"), SuppressUnmanagedCodeSecurity] | ||
1855 | public static extern int SpaceGetNumGeoms(IntPtr space); | ||
1856 | |||
1857 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceGetGeom"), SuppressUnmanagedCodeSecurity] | ||
1858 | public static extern IntPtr SpaceGetGeom(IntPtr space, int i); | ||
1859 | |||
1860 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceGetSublevel"), SuppressUnmanagedCodeSecurity] | ||
1861 | public static extern int SpaceGetSublevel(IntPtr space); | ||
1862 | |||
1863 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceQuery"), SuppressUnmanagedCodeSecurity] | ||
1864 | public static extern bool SpaceQuery(IntPtr space, IntPtr geom); | ||
1865 | |||
1866 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceRemove"), SuppressUnmanagedCodeSecurity] | ||
1867 | public static extern void SpaceRemove(IntPtr space, IntPtr geom); | ||
1868 | |||
1869 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceSetCleanup"), SuppressUnmanagedCodeSecurity] | ||
1870 | public static extern void SpaceSetCleanup(IntPtr space, bool mode); | ||
1871 | |||
1872 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSpaceSetSublevel"), SuppressUnmanagedCodeSecurity] | ||
1873 | public static extern void SpaceSetSublevel(IntPtr space, int sublevel); | ||
1874 | |||
1875 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dSweepAndPruneSpaceCreate"), SuppressUnmanagedCodeSecurity] | ||
1876 | public static extern IntPtr SweepAndPruneSpaceCreate(IntPtr space, int AxisOrder); | ||
1877 | |||
1878 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dVectorScale"), SuppressUnmanagedCodeSecurity] | ||
1879 | public static extern void VectorScale(out dReal a, ref dReal d, int n); | ||
1880 | |||
1881 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldCreate"), SuppressUnmanagedCodeSecurity] | ||
1882 | public static extern IntPtr WorldCreate(); | ||
1883 | |||
1884 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldDestroy"), SuppressUnmanagedCodeSecurity] | ||
1885 | public static extern void WorldDestroy(IntPtr world); | ||
1886 | |||
1887 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAutoDisableAverageSamplesCount"), SuppressUnmanagedCodeSecurity] | ||
1888 | public static extern int WorldGetAutoDisableAverageSamplesCount(IntPtr world); | ||
1889 | |||
1890 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAutoDisableAngularThreshold"), SuppressUnmanagedCodeSecurity] | ||
1891 | public static extern dReal WorldGetAutoDisableAngularThreshold(IntPtr world); | ||
1892 | |||
1893 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAutoDisableFlag"), SuppressUnmanagedCodeSecurity] | ||
1894 | public static extern bool WorldGetAutoDisableFlag(IntPtr world); | ||
1895 | |||
1896 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAutoDisableLinearThreshold"), SuppressUnmanagedCodeSecurity] | ||
1897 | public static extern dReal WorldGetAutoDisableLinearThreshold(IntPtr world); | ||
1898 | |||
1899 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAutoDisableSteps"), SuppressUnmanagedCodeSecurity] | ||
1900 | public static extern int WorldGetAutoDisableSteps(IntPtr world); | ||
1901 | |||
1902 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAutoDisableTime"), SuppressUnmanagedCodeSecurity] | ||
1903 | public static extern dReal WorldGetAutoDisableTime(IntPtr world); | ||
1904 | |||
1905 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAutoEnableDepthSF1"), SuppressUnmanagedCodeSecurity] | ||
1906 | public static extern int WorldGetAutoEnableDepthSF1(IntPtr world); | ||
1907 | |||
1908 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetCFM"), SuppressUnmanagedCodeSecurity] | ||
1909 | public static extern dReal WorldGetCFM(IntPtr world); | ||
1910 | |||
1911 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetERP"), SuppressUnmanagedCodeSecurity] | ||
1912 | public static extern dReal WorldGetERP(IntPtr world); | ||
1913 | |||
1914 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetGravity"), SuppressUnmanagedCodeSecurity] | ||
1915 | public static extern void WorldGetGravity(IntPtr world, out Vector3 gravity); | ||
1916 | |||
1917 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetGravity"), SuppressUnmanagedCodeSecurity] | ||
1918 | public static extern void WorldGetGravity(IntPtr world, out dReal X); | ||
1919 | |||
1920 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetContactMaxCorrectingVel"), SuppressUnmanagedCodeSecurity] | ||
1921 | public static extern dReal WorldGetContactMaxCorrectingVel(IntPtr world); | ||
1922 | |||
1923 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetContactSurfaceLayer"), SuppressUnmanagedCodeSecurity] | ||
1924 | public static extern dReal WorldGetContactSurfaceLayer(IntPtr world); | ||
1925 | |||
1926 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAngularDamping"), SuppressUnmanagedCodeSecurity] | ||
1927 | public static extern dReal WorldGetAngularDamping(IntPtr world); | ||
1928 | |||
1929 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetAngularDampingThreshold"), SuppressUnmanagedCodeSecurity] | ||
1930 | public static extern dReal WorldGetAngularDampingThreshold(IntPtr world); | ||
1931 | |||
1932 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetLinearDamping"), SuppressUnmanagedCodeSecurity] | ||
1933 | public static extern dReal WorldGetLinearDamping(IntPtr world); | ||
1934 | |||
1935 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetLinearDampingThreshold"), SuppressUnmanagedCodeSecurity] | ||
1936 | public static extern dReal WorldGetLinearDampingThreshold(IntPtr world); | ||
1937 | |||
1938 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetQuickStepNumIterations"), SuppressUnmanagedCodeSecurity] | ||
1939 | public static extern int WorldGetQuickStepNumIterations(IntPtr world); | ||
1940 | |||
1941 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetQuickStepW"), SuppressUnmanagedCodeSecurity] | ||
1942 | public static extern dReal WorldGetQuickStepW(IntPtr world); | ||
1943 | |||
1944 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldGetMaxAngularSpeed"), SuppressUnmanagedCodeSecurity] | ||
1945 | public static extern dReal WorldGetMaxAngularSpeed(IntPtr world); | ||
1946 | |||
1947 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldImpulseToForce"), SuppressUnmanagedCodeSecurity] | ||
1948 | public static extern void WorldImpulseToForce(IntPtr world, dReal stepsize, dReal ix, dReal iy, dReal iz, out Vector3 force); | ||
1949 | |||
1950 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldImpulseToForce"), SuppressUnmanagedCodeSecurity] | ||
1951 | public static extern void WorldImpulseToForce(IntPtr world, dReal stepsize, dReal ix, dReal iy, dReal iz, out dReal forceX); | ||
1952 | |||
1953 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldQuickStep"), SuppressUnmanagedCodeSecurity] | ||
1954 | public static extern void WorldQuickStep(IntPtr world, dReal stepsize); | ||
1955 | |||
1956 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAngularDamping"), SuppressUnmanagedCodeSecurity] | ||
1957 | public static extern void WorldSetAngularDamping(IntPtr world, dReal scale); | ||
1958 | |||
1959 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAngularDampingThreshold"), SuppressUnmanagedCodeSecurity] | ||
1960 | public static extern void WorldSetAngularDampingThreshold(IntPtr world, dReal threshold); | ||
1961 | |||
1962 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAutoDisableAngularThreshold"), SuppressUnmanagedCodeSecurity] | ||
1963 | public static extern void WorldSetAutoDisableAngularThreshold(IntPtr world, dReal angular_threshold); | ||
1964 | |||
1965 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAutoDisableAverageSamplesCount"), SuppressUnmanagedCodeSecurity] | ||
1966 | public static extern void WorldSetAutoDisableAverageSamplesCount(IntPtr world, int average_samples_count); | ||
1967 | |||
1968 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAutoDisableFlag"), SuppressUnmanagedCodeSecurity] | ||
1969 | public static extern void WorldSetAutoDisableFlag(IntPtr world, bool do_auto_disable); | ||
1970 | |||
1971 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAutoDisableLinearThreshold"), SuppressUnmanagedCodeSecurity] | ||
1972 | public static extern void WorldSetAutoDisableLinearThreshold(IntPtr world, dReal linear_threshold); | ||
1973 | |||
1974 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAutoDisableSteps"), SuppressUnmanagedCodeSecurity] | ||
1975 | public static extern void WorldSetAutoDisableSteps(IntPtr world, int steps); | ||
1976 | |||
1977 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAutoDisableTime"), SuppressUnmanagedCodeSecurity] | ||
1978 | public static extern void WorldSetAutoDisableTime(IntPtr world, dReal time); | ||
1979 | |||
1980 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetAutoEnableDepthSF1"), SuppressUnmanagedCodeSecurity] | ||
1981 | public static extern void WorldSetAutoEnableDepthSF1(IntPtr world, int autoEnableDepth); | ||
1982 | |||
1983 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetCFM"), SuppressUnmanagedCodeSecurity] | ||
1984 | public static extern void WorldSetCFM(IntPtr world, dReal cfm); | ||
1985 | |||
1986 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetContactMaxCorrectingVel"), SuppressUnmanagedCodeSecurity] | ||
1987 | public static extern void WorldSetContactMaxCorrectingVel(IntPtr world, dReal vel); | ||
1988 | |||
1989 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetContactSurfaceLayer"), SuppressUnmanagedCodeSecurity] | ||
1990 | public static extern void WorldSetContactSurfaceLayer(IntPtr world, dReal depth); | ||
1991 | |||
1992 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetDamping"), SuppressUnmanagedCodeSecurity] | ||
1993 | public static extern void WorldSetDamping(IntPtr world, dReal linear_scale, dReal angular_scale); | ||
1994 | |||
1995 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetERP"), SuppressUnmanagedCodeSecurity] | ||
1996 | public static extern void WorldSetERP(IntPtr world, dReal erp); | ||
1997 | |||
1998 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetGravity"), SuppressUnmanagedCodeSecurity] | ||
1999 | public static extern void WorldSetGravity(IntPtr world, dReal x, dReal y, dReal z); | ||
2000 | |||
2001 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetLinearDamping"), SuppressUnmanagedCodeSecurity] | ||
2002 | public static extern void WorldSetLinearDamping(IntPtr world, dReal scale); | ||
2003 | |||
2004 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetLinearDampingThreshold"), SuppressUnmanagedCodeSecurity] | ||
2005 | public static extern void WorldSetLinearDampingThreshold(IntPtr world, dReal threshold); | ||
2006 | |||
2007 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetQuickStepNumIterations"), SuppressUnmanagedCodeSecurity] | ||
2008 | public static extern void WorldSetQuickStepNumIterations(IntPtr world, int num); | ||
2009 | |||
2010 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetQuickStepW"), SuppressUnmanagedCodeSecurity] | ||
2011 | public static extern void WorldSetQuickStepW(IntPtr world, dReal over_relaxation); | ||
2012 | |||
2013 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldSetMaxAngularSpeed"), SuppressUnmanagedCodeSecurity] | ||
2014 | public static extern void WorldSetMaxAngularSpeed(IntPtr world, dReal max_speed); | ||
2015 | |||
2016 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldStep"), SuppressUnmanagedCodeSecurity] | ||
2017 | public static extern void WorldStep(IntPtr world, dReal stepsize); | ||
2018 | |||
2019 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldStepFast1"), SuppressUnmanagedCodeSecurity] | ||
2020 | public static extern void WorldStepFast1(IntPtr world, dReal stepsize, int maxiterations); | ||
2021 | |||
2022 | [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dWorldExportDIF"), SuppressUnmanagedCodeSecurity] | ||
2023 | public static extern void WorldExportDIF(IntPtr world, string filename, bool append, string prefix); | ||
2024 | } | ||
2025 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs b/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs new file mode 100644 index 0000000..98bfd1c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs | |||
@@ -0,0 +1,1408 @@ | |||
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 OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
34 | using log4net; | ||
35 | |||
36 | namespace OpenSim.Region.PhysicsModule.ODE | ||
37 | { | ||
38 | /// <summary> | ||
39 | /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. | ||
40 | /// </summary> | ||
41 | public enum dParam : int | ||
42 | { | ||
43 | LowStop = 0, | ||
44 | HiStop = 1, | ||
45 | Vel = 2, | ||
46 | FMax = 3, | ||
47 | FudgeFactor = 4, | ||
48 | Bounce = 5, | ||
49 | CFM = 6, | ||
50 | StopERP = 7, | ||
51 | StopCFM = 8, | ||
52 | LoStop2 = 256, | ||
53 | HiStop2 = 257, | ||
54 | Vel2 = 258, | ||
55 | FMax2 = 259, | ||
56 | StopERP2 = 7 + 256, | ||
57 | StopCFM2 = 8 + 256, | ||
58 | LoStop3 = 512, | ||
59 | HiStop3 = 513, | ||
60 | Vel3 = 514, | ||
61 | FMax3 = 515, | ||
62 | StopERP3 = 7 + 512, | ||
63 | StopCFM3 = 8 + 512 | ||
64 | } | ||
65 | |||
66 | public class OdeCharacter : PhysicsActor | ||
67 | { | ||
68 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
69 | |||
70 | private Vector3 _position; | ||
71 | private d.Vector3 _zeroPosition; | ||
72 | private bool _zeroFlag = false; | ||
73 | private bool m_lastUpdateSent = false; | ||
74 | private Vector3 _velocity; | ||
75 | private Vector3 m_taintTargetVelocity; | ||
76 | private Vector3 _target_velocity; | ||
77 | private Vector3 _acceleration; | ||
78 | private Vector3 m_rotationalVelocity; | ||
79 | private float m_mass = 80f; | ||
80 | private float m_density = 60f; | ||
81 | private bool m_pidControllerActive = true; | ||
82 | private float PID_D = 800.0f; | ||
83 | private float PID_P = 900.0f; | ||
84 | //private static float POSTURE_SERVO = 10000.0f; | ||
85 | private float CAPSULE_RADIUS = 0.37f; | ||
86 | private float CAPSULE_LENGTH = 2.140599f; | ||
87 | private float m_tensor = 3800000f; | ||
88 | // private float heightFudgeFactor = 0.52f; | ||
89 | private float walkDivisor = 1.3f; | ||
90 | private float runDivisor = 0.8f; | ||
91 | private bool flying = false; | ||
92 | private bool m_iscolliding = false; | ||
93 | private bool m_iscollidingGround = false; | ||
94 | private bool m_wascolliding = false; | ||
95 | private bool m_wascollidingGround = false; | ||
96 | private bool m_iscollidingObj = false; | ||
97 | private bool m_alwaysRun = false; | ||
98 | private bool m_hackSentFall = false; | ||
99 | private bool m_hackSentFly = false; | ||
100 | private int m_requestedUpdateFrequency = 0; | ||
101 | private Vector3 m_taintPosition; | ||
102 | internal bool m_avatarplanted = false; | ||
103 | /// <summary> | ||
104 | /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force | ||
105 | /// while calculatios are going on | ||
106 | /// </summary> | ||
107 | private Vector3 m_taintForce; | ||
108 | |||
109 | // taints and their non-tainted counterparts | ||
110 | private bool m_isPhysical = false; // the current physical status | ||
111 | private bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing) | ||
112 | internal float MinimumGroundFlightOffset = 3f; | ||
113 | |||
114 | private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes. | ||
115 | |||
116 | /// <summary> | ||
117 | /// Base movement for calculating tilt. | ||
118 | /// </summary> | ||
119 | private float m_tiltBaseMovement = (float)Math.Sqrt(2); | ||
120 | |||
121 | /// <summary> | ||
122 | /// Used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider | ||
123 | /// </summary> | ||
124 | private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f; | ||
125 | |||
126 | private float m_buoyancy = 0f; | ||
127 | |||
128 | // private CollisionLocker ode; | ||
129 | private bool[] m_colliderarr = new bool[11]; | ||
130 | private bool[] m_colliderGroundarr = new bool[11]; | ||
131 | |||
132 | // Default we're a Character | ||
133 | private CollisionCategories m_collisionCategories = (CollisionCategories.Character); | ||
134 | |||
135 | // Default, Collide with Other Geometries, spaces, bodies and characters. | ||
136 | private CollisionCategories m_collisionFlags = (CollisionCategories.Geom | ||
137 | | CollisionCategories.Space | ||
138 | | CollisionCategories.Body | ||
139 | | CollisionCategories.Character | ||
140 | | CollisionCategories.Land); | ||
141 | /// <summary> | ||
142 | /// Body for dynamics simulation | ||
143 | /// </summary> | ||
144 | internal IntPtr Body { get; private set; } | ||
145 | |||
146 | private OdeScene _parent_scene; | ||
147 | |||
148 | /// <summary> | ||
149 | /// Collision geometry | ||
150 | /// </summary> | ||
151 | internal IntPtr Shell { get; private set; } | ||
152 | |||
153 | private IntPtr Amotor = IntPtr.Zero; | ||
154 | private d.Mass ShellMass; | ||
155 | |||
156 | private int m_eventsubscription = 0; | ||
157 | private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
158 | |||
159 | // unique UUID of this character object | ||
160 | internal UUID m_uuid { get; private set; } | ||
161 | internal bool bad = false; | ||
162 | |||
163 | /// <summary> | ||
164 | /// ODE Avatar. | ||
165 | /// </summary> | ||
166 | /// <param name="avName"></param> | ||
167 | /// <param name="parent_scene"></param> | ||
168 | /// <param name="pos"></param> | ||
169 | /// <param name="vel"></param> | ||
170 | /// <param name="size"></param> | ||
171 | /// <param name="pid_d"></param> | ||
172 | /// <param name="pid_p"></param> | ||
173 | /// <param name="capsule_radius"></param> | ||
174 | /// <param name="tensor"></param> | ||
175 | /// <param name="density"> | ||
176 | /// Only used right now to return information to LSL. Not actually used to set mass in ODE! | ||
177 | /// </param> | ||
178 | /// <param name="walk_divisor"></param> | ||
179 | /// <param name="rundivisor"></param> | ||
180 | public OdeCharacter( | ||
181 | String avName, OdeScene parent_scene, Vector3 pos, Vector3 vel, Vector3 size, float pid_d, float pid_p, | ||
182 | float capsule_radius, float tensor, float density, | ||
183 | float walk_divisor, float rundivisor) | ||
184 | { | ||
185 | m_uuid = UUID.Random(); | ||
186 | |||
187 | if (pos.IsFinite()) | ||
188 | { | ||
189 | if (pos.Z > 9999999f) | ||
190 | { | ||
191 | pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5; | ||
192 | } | ||
193 | if (pos.Z < -90000f) | ||
194 | { | ||
195 | pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5; | ||
196 | } | ||
197 | |||
198 | _position = pos; | ||
199 | m_taintPosition = pos; | ||
200 | } | ||
201 | else | ||
202 | { | ||
203 | _position | ||
204 | = new Vector3( | ||
205 | (float)_parent_scene.WorldExtents.X * 0.5f, | ||
206 | (float)_parent_scene.WorldExtents.Y * 0.5f, | ||
207 | parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f); | ||
208 | m_taintPosition = _position; | ||
209 | |||
210 | m_log.WarnFormat("[ODE CHARACTER]: Got NaN Position on Character Create for {0}", avName); | ||
211 | } | ||
212 | |||
213 | _velocity = vel; | ||
214 | m_taintTargetVelocity = vel; | ||
215 | |||
216 | _parent_scene = parent_scene; | ||
217 | |||
218 | PID_D = pid_d; | ||
219 | PID_P = pid_p; | ||
220 | CAPSULE_RADIUS = capsule_radius; | ||
221 | m_tensor = tensor; | ||
222 | m_density = density; | ||
223 | // heightFudgeFactor = height_fudge_factor; | ||
224 | walkDivisor = walk_divisor; | ||
225 | runDivisor = rundivisor; | ||
226 | |||
227 | // m_StandUpRotation = | ||
228 | // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f, | ||
229 | // 0.5f); | ||
230 | |||
231 | // We can set taint and actual to be the same here, since the entire character will be set up when the | ||
232 | // m_tainted_isPhysical is processed. | ||
233 | SetTaintedCapsuleLength(size); | ||
234 | CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; | ||
235 | |||
236 | m_isPhysical = false; // current status: no ODE information exists | ||
237 | m_tainted_isPhysical = true; // new tainted status: need to create ODE information | ||
238 | |||
239 | _parent_scene.AddPhysicsActorTaint(this); | ||
240 | |||
241 | Name = avName; | ||
242 | } | ||
243 | |||
244 | public override int PhysicsActorType | ||
245 | { | ||
246 | get { return (int) ActorTypes.Agent; } | ||
247 | set { return; } | ||
248 | } | ||
249 | |||
250 | /// <summary> | ||
251 | /// If this is set, the avatar will move faster | ||
252 | /// </summary> | ||
253 | public override bool SetAlwaysRun | ||
254 | { | ||
255 | get { return m_alwaysRun; } | ||
256 | set { m_alwaysRun = value; } | ||
257 | } | ||
258 | |||
259 | public override bool Grabbed | ||
260 | { | ||
261 | set { return; } | ||
262 | } | ||
263 | |||
264 | public override bool Selected | ||
265 | { | ||
266 | set { return; } | ||
267 | } | ||
268 | |||
269 | public override float Buoyancy | ||
270 | { | ||
271 | get { return m_buoyancy; } | ||
272 | set { m_buoyancy = value; } | ||
273 | } | ||
274 | |||
275 | public override bool FloatOnWater | ||
276 | { | ||
277 | set { return; } | ||
278 | } | ||
279 | |||
280 | public override bool IsPhysical | ||
281 | { | ||
282 | get { return m_isPhysical; } | ||
283 | set { return; } | ||
284 | } | ||
285 | |||
286 | public override bool ThrottleUpdates | ||
287 | { | ||
288 | get { return false; } | ||
289 | set { return; } | ||
290 | } | ||
291 | |||
292 | public override bool Flying | ||
293 | { | ||
294 | get { return flying; } | ||
295 | set | ||
296 | { | ||
297 | flying = value; | ||
298 | // m_log.DebugFormat("[ODE CHARACTER]: Set OdeCharacter Flying to {0}", flying); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | /// <summary> | ||
303 | /// Returns if the avatar is colliding in general. | ||
304 | /// This includes the ground and objects and avatar. | ||
305 | /// </summary> | ||
306 | public override bool IsColliding | ||
307 | { | ||
308 | get { return m_iscolliding; } | ||
309 | set | ||
310 | { | ||
311 | int i; | ||
312 | int truecount = 0; | ||
313 | int falsecount = 0; | ||
314 | |||
315 | if (m_colliderarr.Length >= 10) | ||
316 | { | ||
317 | for (i = 0; i < 10; i++) | ||
318 | { | ||
319 | m_colliderarr[i] = m_colliderarr[i + 1]; | ||
320 | } | ||
321 | } | ||
322 | m_colliderarr[10] = value; | ||
323 | |||
324 | for (i = 0; i < 11; i++) | ||
325 | { | ||
326 | if (m_colliderarr[i]) | ||
327 | { | ||
328 | truecount++; | ||
329 | } | ||
330 | else | ||
331 | { | ||
332 | falsecount++; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | // Equal truecounts and false counts means we're colliding with something. | ||
337 | |||
338 | if (falsecount > 1.2*truecount) | ||
339 | { | ||
340 | m_iscolliding = false; | ||
341 | } | ||
342 | else | ||
343 | { | ||
344 | m_iscolliding = true; | ||
345 | } | ||
346 | |||
347 | if (m_wascolliding != m_iscolliding) | ||
348 | { | ||
349 | //base.SendCollisionUpdate(new CollisionEventUpdate()); | ||
350 | } | ||
351 | |||
352 | m_wascolliding = m_iscolliding; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | /// <summary> | ||
357 | /// Returns if an avatar is colliding with the ground | ||
358 | /// </summary> | ||
359 | public override bool CollidingGround | ||
360 | { | ||
361 | get { return m_iscollidingGround; } | ||
362 | set | ||
363 | { | ||
364 | // Collisions against the ground are not really reliable | ||
365 | // So, to get a consistant value we have to average the current result over time | ||
366 | // Currently we use 1 second = 10 calls to this. | ||
367 | int i; | ||
368 | int truecount = 0; | ||
369 | int falsecount = 0; | ||
370 | |||
371 | if (m_colliderGroundarr.Length >= 10) | ||
372 | { | ||
373 | for (i = 0; i < 10; i++) | ||
374 | { | ||
375 | m_colliderGroundarr[i] = m_colliderGroundarr[i + 1]; | ||
376 | } | ||
377 | } | ||
378 | m_colliderGroundarr[10] = value; | ||
379 | |||
380 | for (i = 0; i < 11; i++) | ||
381 | { | ||
382 | if (m_colliderGroundarr[i]) | ||
383 | { | ||
384 | truecount++; | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | falsecount++; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | // Equal truecounts and false counts means we're colliding with something. | ||
393 | |||
394 | if (falsecount > 1.2*truecount) | ||
395 | { | ||
396 | m_iscollidingGround = false; | ||
397 | } | ||
398 | else | ||
399 | { | ||
400 | m_iscollidingGround = true; | ||
401 | } | ||
402 | if (m_wascollidingGround != m_iscollidingGround) | ||
403 | { | ||
404 | //base.SendCollisionUpdate(new CollisionEventUpdate()); | ||
405 | } | ||
406 | m_wascollidingGround = m_iscollidingGround; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | /// <summary> | ||
411 | /// Returns if the avatar is colliding with an object | ||
412 | /// </summary> | ||
413 | public override bool CollidingObj | ||
414 | { | ||
415 | get { return m_iscollidingObj; } | ||
416 | set | ||
417 | { | ||
418 | m_iscollidingObj = value; | ||
419 | if (value && !m_avatarplanted) | ||
420 | m_pidControllerActive = false; | ||
421 | else | ||
422 | m_pidControllerActive = true; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | /// <summary> | ||
427 | /// turn the PID controller on or off. | ||
428 | /// The PID Controller will turn on all by itself in many situations | ||
429 | /// </summary> | ||
430 | /// <param name="status"></param> | ||
431 | public void SetPidStatus(bool status) | ||
432 | { | ||
433 | m_pidControllerActive = status; | ||
434 | } | ||
435 | |||
436 | public override bool Stopped | ||
437 | { | ||
438 | get { return _zeroFlag; } | ||
439 | } | ||
440 | |||
441 | /// <summary> | ||
442 | /// This 'puts' an avatar somewhere in the physics space. | ||
443 | /// Not really a good choice unless you 'know' it's a good | ||
444 | /// spot otherwise you're likely to orbit the avatar. | ||
445 | /// </summary> | ||
446 | public override Vector3 Position | ||
447 | { | ||
448 | get { return _position; } | ||
449 | set | ||
450 | { | ||
451 | if (Body == IntPtr.Zero || Shell == IntPtr.Zero) | ||
452 | { | ||
453 | if (value.IsFinite()) | ||
454 | { | ||
455 | if (value.Z > 9999999f) | ||
456 | { | ||
457 | value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5; | ||
458 | } | ||
459 | if (value.Z < -90000f) | ||
460 | { | ||
461 | value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5; | ||
462 | } | ||
463 | |||
464 | m_taintPosition = value; | ||
465 | _parent_scene.AddPhysicsActorTaint(this); | ||
466 | } | ||
467 | else | ||
468 | { | ||
469 | m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Position from Scene on character {0}", Name); | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | |||
475 | public override Vector3 RotationalVelocity | ||
476 | { | ||
477 | get { return m_rotationalVelocity; } | ||
478 | set { m_rotationalVelocity = value; } | ||
479 | } | ||
480 | |||
481 | /// <summary> | ||
482 | /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight | ||
483 | /// and use it to offset landings properly | ||
484 | /// </summary> | ||
485 | public override Vector3 Size | ||
486 | { | ||
487 | get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); } | ||
488 | set | ||
489 | { | ||
490 | SetTaintedCapsuleLength(value); | ||
491 | |||
492 | // If we reset velocity here, then an avatar stalls when it crosses a border for the first time | ||
493 | // (as the height of the new root agent is set). | ||
494 | // Velocity = Vector3.Zero; | ||
495 | |||
496 | _parent_scene.AddPhysicsActorTaint(this); | ||
497 | } | ||
498 | } | ||
499 | |||
500 | private void SetTaintedCapsuleLength(Vector3 size) | ||
501 | { | ||
502 | if (size.IsFinite()) | ||
503 | { | ||
504 | m_pidControllerActive = true; | ||
505 | |||
506 | m_tainted_CAPSULE_LENGTH = size.Z - CAPSULE_RADIUS * 2.0f; | ||
507 | |||
508 | // m_log.InfoFormat("[ODE CHARACTER]: Size = {0}, Capsule Length = {1} (Capsule Radius = {2})", | ||
509 | // size, m_tainted_CAPSULE_LENGTH, CAPSULE_RADIUS); | ||
510 | } | ||
511 | else | ||
512 | { | ||
513 | m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Size for {0} in {1}", Name, _parent_scene.PhysicsSceneName); | ||
514 | } | ||
515 | } | ||
516 | |||
517 | private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector) | ||
518 | { | ||
519 | movementVector.Z = 0f; | ||
520 | float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y)); | ||
521 | if (magnitude < 0.1f) return; | ||
522 | |||
523 | // normalize the velocity vector | ||
524 | float invMagnitude = 1.0f / magnitude; | ||
525 | movementVector.X *= invMagnitude; | ||
526 | movementVector.Y *= invMagnitude; | ||
527 | |||
528 | // if we change the capsule heading too often, the capsule can fall down | ||
529 | // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw), | ||
530 | // meaning only 4 possible capsule tilt orientations | ||
531 | if (movementVector.X > 0) | ||
532 | { | ||
533 | // east | ||
534 | if (movementVector.Y > 0) | ||
535 | { | ||
536 | // northeast | ||
537 | movementVector.X = m_tiltBaseMovement; | ||
538 | movementVector.Y = m_tiltBaseMovement; | ||
539 | } | ||
540 | else | ||
541 | { | ||
542 | // southeast | ||
543 | movementVector.X = m_tiltBaseMovement; | ||
544 | movementVector.Y = -m_tiltBaseMovement; | ||
545 | } | ||
546 | } | ||
547 | else | ||
548 | { | ||
549 | // west | ||
550 | if (movementVector.Y > 0) | ||
551 | { | ||
552 | // northwest | ||
553 | movementVector.X = -m_tiltBaseMovement; | ||
554 | movementVector.Y = m_tiltBaseMovement; | ||
555 | } | ||
556 | else | ||
557 | { | ||
558 | // southwest | ||
559 | movementVector.X = -m_tiltBaseMovement; | ||
560 | movementVector.Y = -m_tiltBaseMovement; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | // movementVector.Z is zero | ||
565 | |||
566 | // calculate tilt components based on desired amount of tilt and current (snapped) heading. | ||
567 | // the "-" sign is to force the tilt to be OPPOSITE the direction of movement. | ||
568 | float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane; | ||
569 | float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane; | ||
570 | |||
571 | //m_log.Debug("[ODE CHARACTER]: changing avatar tilt"); | ||
572 | d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent); | ||
573 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced | ||
574 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent); | ||
575 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop | ||
576 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f); | ||
577 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop | ||
578 | } | ||
579 | |||
580 | /// <summary> | ||
581 | /// Uses the capped cyllinder volume formula to calculate the avatar's mass. | ||
582 | /// This may be used in calculations in the scene/scenepresence | ||
583 | /// </summary> | ||
584 | public override float Mass | ||
585 | { | ||
586 | get | ||
587 | { | ||
588 | float AVvolume = (float)(Math.PI * Math.Pow(CAPSULE_RADIUS, 2) * CAPSULE_LENGTH); | ||
589 | return m_density * AVvolume; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | public override void link(PhysicsActor obj) {} | ||
594 | |||
595 | public override void delink() {} | ||
596 | |||
597 | public override void LockAngularMotion(byte axislocks) {} | ||
598 | |||
599 | // This code is very useful. Written by DanX0r. We're just not using it right now. | ||
600 | // Commented out to prevent a warning. | ||
601 | // | ||
602 | // private void standupStraight() | ||
603 | // { | ||
604 | // // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air. | ||
605 | // // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you | ||
606 | // // change appearance and when you enter the simulator | ||
607 | // // After this routine is done, the amotor stabilizes much quicker | ||
608 | // d.Vector3 feet; | ||
609 | // d.Vector3 head; | ||
610 | // d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet); | ||
611 | // d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head); | ||
612 | // float posture = head.Z - feet.Z; | ||
613 | |||
614 | // // restoring force proportional to lack of posture: | ||
615 | // float servo = (2.5f - posture) * POSTURE_SERVO; | ||
616 | // d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f); | ||
617 | // d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f); | ||
618 | // //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); | ||
619 | // //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyFArotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); | ||
620 | // } | ||
621 | |||
622 | public override Vector3 Force | ||
623 | { | ||
624 | get { return _target_velocity; } | ||
625 | set { return; } | ||
626 | } | ||
627 | |||
628 | public override int VehicleType | ||
629 | { | ||
630 | get { return 0; } | ||
631 | set { return; } | ||
632 | } | ||
633 | |||
634 | public override void VehicleFloatParam(int param, float value) | ||
635 | { | ||
636 | } | ||
637 | |||
638 | public override void VehicleVectorParam(int param, Vector3 value) | ||
639 | { | ||
640 | } | ||
641 | |||
642 | public override void VehicleRotationParam(int param, Quaternion rotation) | ||
643 | { | ||
644 | } | ||
645 | |||
646 | public override void VehicleFlags(int param, bool remove) | ||
647 | { | ||
648 | } | ||
649 | |||
650 | public override void SetVolumeDetect(int param) | ||
651 | { | ||
652 | } | ||
653 | |||
654 | public override Vector3 CenterOfMass | ||
655 | { | ||
656 | get { return Vector3.Zero; } | ||
657 | } | ||
658 | |||
659 | public override Vector3 GeometricCenter | ||
660 | { | ||
661 | get { return Vector3.Zero; } | ||
662 | } | ||
663 | |||
664 | public override PrimitiveBaseShape Shape | ||
665 | { | ||
666 | set { return; } | ||
667 | } | ||
668 | |||
669 | public override Vector3 TargetVelocity | ||
670 | { | ||
671 | get | ||
672 | { | ||
673 | return m_taintTargetVelocity; | ||
674 | } | ||
675 | |||
676 | set | ||
677 | { | ||
678 | Velocity = value; | ||
679 | } | ||
680 | } | ||
681 | |||
682 | |||
683 | public override Vector3 Velocity | ||
684 | { | ||
685 | get | ||
686 | { | ||
687 | // There's a problem with Vector3.Zero! Don't Use it Here! | ||
688 | if (_zeroFlag) | ||
689 | return Vector3.Zero; | ||
690 | m_lastUpdateSent = false; | ||
691 | return _velocity; | ||
692 | } | ||
693 | |||
694 | set | ||
695 | { | ||
696 | if (value.IsFinite()) | ||
697 | { | ||
698 | m_pidControllerActive = true; | ||
699 | m_taintTargetVelocity = value; | ||
700 | _parent_scene.AddPhysicsActorTaint(this); | ||
701 | } | ||
702 | else | ||
703 | { | ||
704 | m_log.WarnFormat("[ODE CHARACTER]: Got a NaN velocity from Scene for {0}", Name); | ||
705 | } | ||
706 | |||
707 | // m_log.DebugFormat("[PHYSICS]: Set target velocity of {0}", m_taintTargetVelocity); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | public override Vector3 Torque | ||
712 | { | ||
713 | get { return Vector3.Zero; } | ||
714 | set { return; } | ||
715 | } | ||
716 | |||
717 | public override float CollisionScore | ||
718 | { | ||
719 | get { return 0f; } | ||
720 | set { } | ||
721 | } | ||
722 | |||
723 | public override bool Kinematic | ||
724 | { | ||
725 | get { return false; } | ||
726 | set { } | ||
727 | } | ||
728 | |||
729 | public override Quaternion Orientation | ||
730 | { | ||
731 | get { return Quaternion.Identity; } | ||
732 | set { | ||
733 | //Matrix3 or = Orientation.ToRotationMatrix(); | ||
734 | //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22); | ||
735 | //d.BodySetRotation(Body, ref ord); | ||
736 | } | ||
737 | } | ||
738 | |||
739 | public override Vector3 Acceleration | ||
740 | { | ||
741 | get { return _acceleration; } | ||
742 | set { _acceleration = value; } | ||
743 | } | ||
744 | |||
745 | /// <summary> | ||
746 | /// Adds the force supplied to the Target Velocity | ||
747 | /// The PID controller takes this target velocity and tries to make it a reality | ||
748 | /// </summary> | ||
749 | /// <param name="force"></param> | ||
750 | public override void AddForce(Vector3 force, bool pushforce) | ||
751 | { | ||
752 | if (force.IsFinite()) | ||
753 | { | ||
754 | if (pushforce) | ||
755 | { | ||
756 | m_pidControllerActive = false; | ||
757 | force *= 100f; | ||
758 | m_taintForce += force; | ||
759 | _parent_scene.AddPhysicsActorTaint(this); | ||
760 | |||
761 | // If uncommented, things get pushed off world | ||
762 | // | ||
763 | // m_log.Debug("Push!"); | ||
764 | // m_taintTargetVelocity.X += force.X; | ||
765 | // m_taintTargetVelocity.Y += force.Y; | ||
766 | // m_taintTargetVelocity.Z += force.Z; | ||
767 | } | ||
768 | else | ||
769 | { | ||
770 | m_pidControllerActive = true; | ||
771 | m_taintTargetVelocity += force; | ||
772 | } | ||
773 | } | ||
774 | else | ||
775 | { | ||
776 | m_log.WarnFormat("[ODE CHARACTER]: Got a NaN force applied to {0}", Name); | ||
777 | } | ||
778 | //m_lastUpdateSent = false; | ||
779 | } | ||
780 | |||
781 | public override void AddAngularForce(Vector3 force, bool pushforce) | ||
782 | { | ||
783 | } | ||
784 | |||
785 | public override void SetMomentum(Vector3 momentum) | ||
786 | { | ||
787 | } | ||
788 | |||
789 | /// <summary> | ||
790 | /// Called from Simulate | ||
791 | /// This is the avatar's movement control + PID Controller | ||
792 | /// </summary> | ||
793 | /// <param name="defects">The character will be added to this list if there is something wrong (non-finite | ||
794 | /// position or velocity). | ||
795 | /// </param> | ||
796 | internal void Move(List<OdeCharacter> defects) | ||
797 | { | ||
798 | // no lock; for now it's only called from within Simulate() | ||
799 | |||
800 | // If the PID Controller isn't active then we set our force | ||
801 | // calculating base velocity to the current position | ||
802 | |||
803 | if (Body == IntPtr.Zero) | ||
804 | return; | ||
805 | |||
806 | if (m_pidControllerActive == false) | ||
807 | { | ||
808 | _zeroPosition = d.BodyGetPosition(Body); | ||
809 | } | ||
810 | //PidStatus = true; | ||
811 | |||
812 | d.Vector3 localpos = d.BodyGetPosition(Body); | ||
813 | Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z); | ||
814 | |||
815 | if (!localPos.IsFinite()) | ||
816 | { | ||
817 | m_log.WarnFormat( | ||
818 | "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.", | ||
819 | localPos, Name); | ||
820 | |||
821 | defects.Add(this); | ||
822 | |||
823 | return; | ||
824 | } | ||
825 | |||
826 | Vector3 vec = Vector3.Zero; | ||
827 | d.Vector3 vel = d.BodyGetLinearVel(Body); | ||
828 | |||
829 | // m_log.DebugFormat( | ||
830 | // "[ODE CHARACTER]: Current velocity in Move() is <{0},{1},{2}>, target {3} for {4}", | ||
831 | // vel.X, vel.Y, vel.Z, _target_velocity, Name); | ||
832 | |||
833 | float movementdivisor = 1f; | ||
834 | |||
835 | if (!m_alwaysRun) | ||
836 | { | ||
837 | movementdivisor = walkDivisor; | ||
838 | } | ||
839 | else | ||
840 | { | ||
841 | movementdivisor = runDivisor; | ||
842 | } | ||
843 | |||
844 | // if velocity is zero, use position control; otherwise, velocity control | ||
845 | if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding) | ||
846 | { | ||
847 | // keep track of where we stopped. No more slippin' & slidin' | ||
848 | if (!_zeroFlag) | ||
849 | { | ||
850 | _zeroFlag = true; | ||
851 | _zeroPosition = d.BodyGetPosition(Body); | ||
852 | } | ||
853 | |||
854 | if (m_pidControllerActive) | ||
855 | { | ||
856 | // We only want to deactivate the PID Controller if we think we want to have our surrogate | ||
857 | // react to the physics scene by moving it's position. | ||
858 | // Avatar to Avatar collisions | ||
859 | // Prim to avatar collisions | ||
860 | |||
861 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
862 | vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); | ||
863 | vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y)* (PID_P * 2); | ||
864 | if (flying) | ||
865 | { | ||
866 | vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; | ||
867 | } | ||
868 | } | ||
869 | //PidStatus = true; | ||
870 | } | ||
871 | else | ||
872 | { | ||
873 | m_pidControllerActive = true; | ||
874 | _zeroFlag = false; | ||
875 | if (m_iscolliding && !flying) | ||
876 | { | ||
877 | // We're standing on something | ||
878 | vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D); | ||
879 | vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D); | ||
880 | } | ||
881 | else if (m_iscolliding && flying) | ||
882 | { | ||
883 | // We're flying and colliding with something | ||
884 | vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16); | ||
885 | vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16); | ||
886 | } | ||
887 | else if (!m_iscolliding && flying) | ||
888 | { | ||
889 | // we're in mid air suspended | ||
890 | vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6); | ||
891 | vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6); | ||
892 | |||
893 | // m_log.DebugFormat( | ||
894 | // "[ODE CHARACTER]: !m_iscolliding && flying, vec {0}, _target_velocity {1}, movementdivisor {2}, vel {3}", | ||
895 | // vec, _target_velocity, movementdivisor, vel); | ||
896 | } | ||
897 | |||
898 | if (flying) | ||
899 | { | ||
900 | // This also acts as anti-gravity so that we hover when flying rather than fall. | ||
901 | vec.Z = (_target_velocity.Z - vel.Z) * (PID_D); | ||
902 | } | ||
903 | else | ||
904 | { | ||
905 | if (m_iscolliding && _target_velocity.Z > 0.0f) | ||
906 | { | ||
907 | // We're colliding with something and we're not flying but we're moving | ||
908 | // This means we're walking or running. | ||
909 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
910 | vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; | ||
911 | vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; | ||
912 | vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; | ||
913 | } | ||
914 | else if (!m_iscolliding) | ||
915 | { | ||
916 | // we're not colliding and we're not flying so that means we're falling! | ||
917 | // m_iscolliding includes collisions with the ground. | ||
918 | vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; | ||
919 | vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; | ||
920 | } | ||
921 | } | ||
922 | } | ||
923 | |||
924 | if (flying) | ||
925 | { | ||
926 | // Anti-gravity so that we hover when flying rather than fall. | ||
927 | vec.Z += ((-1 * _parent_scene.gravityz) * m_mass); | ||
928 | |||
929 | //Added for auto fly height. Kitto Flora | ||
930 | //d.Vector3 pos = d.BodyGetPosition(Body); | ||
931 | float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; | ||
932 | |||
933 | if (_position.Z < target_altitude) | ||
934 | { | ||
935 | vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f; | ||
936 | } | ||
937 | // end add Kitto Flora | ||
938 | } | ||
939 | |||
940 | if (vec.IsFinite()) | ||
941 | { | ||
942 | // Apply the total force acting on this avatar | ||
943 | d.BodyAddForce(Body, vec.X, vec.Y, vec.Z); | ||
944 | |||
945 | if (!_zeroFlag) | ||
946 | AlignAvatarTiltWithCurrentDirectionOfMovement(vec); | ||
947 | } | ||
948 | else | ||
949 | { | ||
950 | m_log.WarnFormat( | ||
951 | "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.", | ||
952 | vec, Name); | ||
953 | |||
954 | defects.Add(this); | ||
955 | |||
956 | return; | ||
957 | } | ||
958 | |||
959 | d.Vector3 newVel = d.BodyGetLinearVel(Body); | ||
960 | if (newVel.X >= 256 || newVel.X <= 256 || newVel.Y >= 256 || newVel.Y <= 256 || newVel.Z >= 256 || newVel.Z <= 256) | ||
961 | { | ||
962 | // m_log.DebugFormat( | ||
963 | // "[ODE CHARACTER]: Limiting falling velocity from {0} to {1} for {2}", newVel.Z, -9.8, Name); | ||
964 | |||
965 | newVel.X = Util.Clamp<float>(newVel.X, -255f, 255f); | ||
966 | newVel.Y = Util.Clamp<float>(newVel.Y, -255f, 255f); | ||
967 | |||
968 | if (!flying) | ||
969 | newVel.Z | ||
970 | = Util.Clamp<float>( | ||
971 | newVel.Z, -_parent_scene.AvatarTerminalVelocity, _parent_scene.AvatarTerminalVelocity); | ||
972 | else | ||
973 | newVel.Z = Util.Clamp<float>(newVel.Z, -255f, 255f); | ||
974 | |||
975 | d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | /// <summary> | ||
980 | /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. | ||
981 | /// </summary> | ||
982 | /// <param name="defects">The character will be added to this list if there is something wrong (non-finite | ||
983 | /// position or velocity). | ||
984 | /// </param> | ||
985 | internal void UpdatePositionAndVelocity(List<OdeCharacter> defects) | ||
986 | { | ||
987 | // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! | ||
988 | d.Vector3 newPos; | ||
989 | try | ||
990 | { | ||
991 | newPos = d.BodyGetPosition(Body); | ||
992 | } | ||
993 | catch (NullReferenceException) | ||
994 | { | ||
995 | bad = true; | ||
996 | defects.Add(this); | ||
997 | newPos = new d.Vector3(_position.X, _position.Y, _position.Z); | ||
998 | base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! | ||
999 | m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); | ||
1000 | |||
1001 | return; | ||
1002 | } | ||
1003 | |||
1004 | // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) | ||
1005 | if (newPos.X < 0.0f) newPos.X = 0.0f; | ||
1006 | if (newPos.Y < 0.0f) newPos.Y = 0.0f; | ||
1007 | if (newPos.X > (int)_parent_scene.WorldExtents.X - 0.05f) newPos.X = (int)_parent_scene.WorldExtents.X - 0.05f; | ||
1008 | if (newPos.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) newPos.Y = (int)_parent_scene.WorldExtents.Y - 0.05f; | ||
1009 | |||
1010 | _position.X = newPos.X; | ||
1011 | _position.Y = newPos.Y; | ||
1012 | _position.Z = newPos.Z; | ||
1013 | |||
1014 | // I think we need to update the taintPosition too -- Diva 12/24/10 | ||
1015 | m_taintPosition = _position; | ||
1016 | |||
1017 | // Did we move last? = zeroflag | ||
1018 | // This helps keep us from sliding all over | ||
1019 | |||
1020 | if (_zeroFlag) | ||
1021 | { | ||
1022 | _velocity = Vector3.Zero; | ||
1023 | |||
1024 | // Did we send out the 'stopped' message? | ||
1025 | if (!m_lastUpdateSent) | ||
1026 | { | ||
1027 | m_lastUpdateSent = true; | ||
1028 | //base.RequestPhysicsterseUpdate(); | ||
1029 | } | ||
1030 | } | ||
1031 | else | ||
1032 | { | ||
1033 | m_lastUpdateSent = false; | ||
1034 | d.Vector3 newVelocity; | ||
1035 | |||
1036 | try | ||
1037 | { | ||
1038 | newVelocity = d.BodyGetLinearVel(Body); | ||
1039 | } | ||
1040 | catch (NullReferenceException) | ||
1041 | { | ||
1042 | newVelocity.X = _velocity.X; | ||
1043 | newVelocity.Y = _velocity.Y; | ||
1044 | newVelocity.Z = _velocity.Z; | ||
1045 | } | ||
1046 | |||
1047 | _velocity.X = newVelocity.X; | ||
1048 | _velocity.Y = newVelocity.Y; | ||
1049 | _velocity.Z = newVelocity.Z; | ||
1050 | |||
1051 | if (_velocity.Z < -6 && !m_hackSentFall) | ||
1052 | { | ||
1053 | m_hackSentFall = true; | ||
1054 | m_pidControllerActive = false; | ||
1055 | } | ||
1056 | else if (flying && !m_hackSentFly) | ||
1057 | { | ||
1058 | //m_hackSentFly = true; | ||
1059 | //base.SendCollisionUpdate(new CollisionEventUpdate()); | ||
1060 | } | ||
1061 | else | ||
1062 | { | ||
1063 | m_hackSentFly = false; | ||
1064 | m_hackSentFall = false; | ||
1065 | } | ||
1066 | } | ||
1067 | } | ||
1068 | |||
1069 | /// <summary> | ||
1070 | /// This creates the Avatar's physical Surrogate in ODE at the position supplied | ||
1071 | /// </summary> | ||
1072 | /// <remarks> | ||
1073 | /// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access | ||
1074 | /// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only | ||
1075 | /// place that is safe to call this routine AvatarGeomAndBodyCreation. | ||
1076 | /// </remarks> | ||
1077 | /// <param name="npositionX"></param> | ||
1078 | /// <param name="npositionY"></param> | ||
1079 | /// <param name="npositionZ"></param> | ||
1080 | /// <param name="tensor"></param> | ||
1081 | private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor) | ||
1082 | { | ||
1083 | if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero)) | ||
1084 | { | ||
1085 | m_log.ErrorFormat( | ||
1086 | "[ODE CHARACTER]: Creating ODE structures for {0} even though some already exist. Shell = {1}, Body = {2}, Amotor = {3}", | ||
1087 | Name, Shell, Body, Amotor); | ||
1088 | } | ||
1089 | |||
1090 | int dAMotorEuler = 1; | ||
1091 | // _parent_scene.waitForSpaceUnlock(_parent_scene.space); | ||
1092 | if (CAPSULE_LENGTH <= 0) | ||
1093 | { | ||
1094 | m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); | ||
1095 | CAPSULE_LENGTH = 0.01f; | ||
1096 | } | ||
1097 | |||
1098 | if (CAPSULE_RADIUS <= 0) | ||
1099 | { | ||
1100 | m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); | ||
1101 | CAPSULE_RADIUS = 0.01f; | ||
1102 | } | ||
1103 | |||
1104 | // lock (OdeScene.UniversalColliderSyncObject) | ||
1105 | Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); | ||
1106 | |||
1107 | d.GeomSetCategoryBits(Shell, (uint)m_collisionCategories); | ||
1108 | d.GeomSetCollideBits(Shell, (uint)m_collisionFlags); | ||
1109 | |||
1110 | d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH); | ||
1111 | Body = d.BodyCreate(_parent_scene.world); | ||
1112 | d.BodySetPosition(Body, npositionX, npositionY, npositionZ); | ||
1113 | |||
1114 | _position.X = npositionX; | ||
1115 | _position.Y = npositionY; | ||
1116 | _position.Z = npositionZ; | ||
1117 | |||
1118 | m_taintPosition = _position; | ||
1119 | |||
1120 | d.BodySetMass(Body, ref ShellMass); | ||
1121 | d.Matrix3 m_caprot; | ||
1122 | // 90 Stand up on the cap of the capped cyllinder | ||
1123 | if (_parent_scene.IsAvCapsuleTilted) | ||
1124 | { | ||
1125 | d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2)); | ||
1126 | } | ||
1127 | else | ||
1128 | { | ||
1129 | d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2)); | ||
1130 | } | ||
1131 | |||
1132 | d.GeomSetRotation(Shell, ref m_caprot); | ||
1133 | d.BodySetRotation(Body, ref m_caprot); | ||
1134 | |||
1135 | d.GeomSetBody(Shell, Body); | ||
1136 | |||
1137 | // The purpose of the AMotor here is to keep the avatar's physical | ||
1138 | // surrogate from rotating while moving | ||
1139 | Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); | ||
1140 | d.JointAttach(Amotor, Body, IntPtr.Zero); | ||
1141 | d.JointSetAMotorMode(Amotor, dAMotorEuler); | ||
1142 | d.JointSetAMotorNumAxes(Amotor, 3); | ||
1143 | d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0); | ||
1144 | d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0); | ||
1145 | d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1); | ||
1146 | d.JointSetAMotorAngle(Amotor, 0, 0); | ||
1147 | d.JointSetAMotorAngle(Amotor, 1, 0); | ||
1148 | d.JointSetAMotorAngle(Amotor, 2, 0); | ||
1149 | |||
1150 | // These lowstops and high stops are effectively (no wiggle room) | ||
1151 | if (_parent_scene.IsAvCapsuleTilted) | ||
1152 | { | ||
1153 | d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f); | ||
1154 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f); | ||
1155 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f); | ||
1156 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f); | ||
1157 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f); | ||
1158 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f); | ||
1159 | } | ||
1160 | else | ||
1161 | { | ||
1162 | #region Documentation of capsule motor LowStop and HighStop parameters | ||
1163 | // Intentionally introduce some tilt into the capsule by setting | ||
1164 | // the motor stops to small epsilon values. This small tilt prevents | ||
1165 | // the capsule from falling into the terrain; a straight-up capsule | ||
1166 | // (with -0..0 motor stops) falls into the terrain for reasons yet | ||
1167 | // to be comprehended in their entirety. | ||
1168 | #endregion | ||
1169 | AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero); | ||
1170 | d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f); | ||
1171 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); | ||
1172 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f); | ||
1173 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced | ||
1174 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop | ||
1175 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop | ||
1176 | } | ||
1177 | |||
1178 | // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the | ||
1179 | // capped cyllinder will fall over | ||
1180 | d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); | ||
1181 | d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor); | ||
1182 | |||
1183 | //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); | ||
1184 | //d.QfromR( | ||
1185 | //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068, | ||
1186 | // | ||
1187 | //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); | ||
1188 | //standupStraight(); | ||
1189 | |||
1190 | _parent_scene.geom_name_map[Shell] = Name; | ||
1191 | _parent_scene.actor_name_map[Shell] = this; | ||
1192 | } | ||
1193 | |||
1194 | /// <summary> | ||
1195 | /// Cleanup the things we use in the scene. | ||
1196 | /// </summary> | ||
1197 | internal void Destroy() | ||
1198 | { | ||
1199 | m_tainted_isPhysical = false; | ||
1200 | _parent_scene.AddPhysicsActorTaint(this); | ||
1201 | } | ||
1202 | |||
1203 | /// <summary> | ||
1204 | /// Used internally to destroy the ODE structures associated with this character. | ||
1205 | /// </summary> | ||
1206 | internal void DestroyOdeStructures() | ||
1207 | { | ||
1208 | // Create avatar capsule and related ODE data | ||
1209 | if (Shell == IntPtr.Zero || Body == IntPtr.Zero || Amotor == IntPtr.Zero) | ||
1210 | { | ||
1211 | m_log.ErrorFormat( | ||
1212 | "[ODE CHARACTER]: Destroying ODE structures for {0} even though some are already null. Shell = {1}, Body = {2}, Amotor = {3}", | ||
1213 | Name, Shell, Body, Amotor); | ||
1214 | } | ||
1215 | |||
1216 | // destroy avatar capsule and related ODE data | ||
1217 | if (Amotor != IntPtr.Zero) | ||
1218 | { | ||
1219 | // Kill the Amotor | ||
1220 | d.JointDestroy(Amotor); | ||
1221 | Amotor = IntPtr.Zero; | ||
1222 | } | ||
1223 | |||
1224 | //kill the Geometry | ||
1225 | // _parent_scene.waitForSpaceUnlock(_parent_scene.space); | ||
1226 | |||
1227 | if (Body != IntPtr.Zero) | ||
1228 | { | ||
1229 | //kill the body | ||
1230 | d.BodyDestroy(Body); | ||
1231 | Body = IntPtr.Zero; | ||
1232 | } | ||
1233 | |||
1234 | if (Shell != IntPtr.Zero) | ||
1235 | { | ||
1236 | // lock (OdeScene.UniversalColliderSyncObject) | ||
1237 | d.GeomDestroy(Shell); | ||
1238 | |||
1239 | _parent_scene.geom_name_map.Remove(Shell); | ||
1240 | _parent_scene.actor_name_map.Remove(Shell); | ||
1241 | |||
1242 | Shell = IntPtr.Zero; | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | public override void CrossingFailure() | ||
1247 | { | ||
1248 | } | ||
1249 | |||
1250 | public override Vector3 PIDTarget { set { return; } } | ||
1251 | public override bool PIDActive | ||
1252 | { | ||
1253 | get { return false; } | ||
1254 | set { return; } | ||
1255 | } | ||
1256 | public override float PIDTau { set { return; } } | ||
1257 | |||
1258 | public override float PIDHoverHeight { set { return; } } | ||
1259 | public override bool PIDHoverActive {get {return false;} set { return; } } | ||
1260 | public override PIDHoverType PIDHoverType { set { return; } } | ||
1261 | public override float PIDHoverTau { set { return; } } | ||
1262 | |||
1263 | public override Quaternion APIDTarget{ set { return; } } | ||
1264 | |||
1265 | public override bool APIDActive{ set { return; } } | ||
1266 | |||
1267 | public override float APIDStrength{ set { return; } } | ||
1268 | |||
1269 | public override float APIDDamping{ set { return; } } | ||
1270 | |||
1271 | public override void SubscribeEvents(int ms) | ||
1272 | { | ||
1273 | m_requestedUpdateFrequency = ms; | ||
1274 | m_eventsubscription = ms; | ||
1275 | |||
1276 | // Don't clear collision event reporting here. This is called directly from scene code and so can lead | ||
1277 | // to a race condition with the simulate loop | ||
1278 | |||
1279 | _parent_scene.AddCollisionEventReporting(this); | ||
1280 | } | ||
1281 | |||
1282 | public override void UnSubscribeEvents() | ||
1283 | { | ||
1284 | _parent_scene.RemoveCollisionEventReporting(this); | ||
1285 | |||
1286 | // Don't clear collision event reporting here. This is called directly from scene code and so can lead | ||
1287 | // to a race condition with the simulate loop | ||
1288 | |||
1289 | m_requestedUpdateFrequency = 0; | ||
1290 | m_eventsubscription = 0; | ||
1291 | } | ||
1292 | |||
1293 | public override void AddCollisionEvent(uint CollidedWith, ContactPoint contact) | ||
1294 | { | ||
1295 | if (m_eventsubscription > 0) | ||
1296 | { | ||
1297 | // m_log.DebugFormat( | ||
1298 | // "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact); | ||
1299 | |||
1300 | CollisionEventsThisFrame.AddCollider(CollidedWith, contact); | ||
1301 | } | ||
1302 | } | ||
1303 | |||
1304 | internal void SendCollisions() | ||
1305 | { | ||
1306 | if (m_eventsubscription > m_requestedUpdateFrequency) | ||
1307 | { | ||
1308 | base.SendCollisionUpdate(CollisionEventsThisFrame); | ||
1309 | |||
1310 | CollisionEventsThisFrame.Clear(); | ||
1311 | m_eventsubscription = 0; | ||
1312 | } | ||
1313 | } | ||
1314 | |||
1315 | public override bool SubscribedEvents() | ||
1316 | { | ||
1317 | if (m_eventsubscription > 0) | ||
1318 | return true; | ||
1319 | return false; | ||
1320 | } | ||
1321 | |||
1322 | internal void ProcessTaints() | ||
1323 | { | ||
1324 | if (m_taintPosition != _position) | ||
1325 | { | ||
1326 | if (Body != IntPtr.Zero) | ||
1327 | { | ||
1328 | d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z); | ||
1329 | _position = m_taintPosition; | ||
1330 | } | ||
1331 | } | ||
1332 | |||
1333 | if (m_taintForce != Vector3.Zero) | ||
1334 | { | ||
1335 | if (Body != IntPtr.Zero) | ||
1336 | { | ||
1337 | // FIXME: This is not a good solution since it's subject to a race condition if a force is another | ||
1338 | // thread sets a new force while we're in this loop (since it could be obliterated by | ||
1339 | // m_taintForce = Vector3.Zero. Need to lock ProcessTaints() when we set a new tainted force. | ||
1340 | d.BodyAddForce(Body, m_taintForce.X, m_taintForce.Y, m_taintForce.Z); | ||
1341 | } | ||
1342 | |||
1343 | m_taintForce = Vector3.Zero; | ||
1344 | } | ||
1345 | |||
1346 | if (m_taintTargetVelocity != _target_velocity) | ||
1347 | _target_velocity = m_taintTargetVelocity; | ||
1348 | |||
1349 | if (m_tainted_isPhysical != m_isPhysical) | ||
1350 | { | ||
1351 | if (m_tainted_isPhysical) | ||
1352 | { | ||
1353 | CreateOdeStructures(_position.X, _position.Y, _position.Z, m_tensor); | ||
1354 | _parent_scene.AddCharacter(this); | ||
1355 | } | ||
1356 | else | ||
1357 | { | ||
1358 | _parent_scene.RemoveCharacter(this); | ||
1359 | DestroyOdeStructures(); | ||
1360 | } | ||
1361 | |||
1362 | m_isPhysical = m_tainted_isPhysical; | ||
1363 | } | ||
1364 | |||
1365 | if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH) | ||
1366 | { | ||
1367 | if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero) | ||
1368 | { | ||
1369 | // m_log.DebugFormat( | ||
1370 | // "[ODE CHARACTER]: Changing capsule size from {0} to {1} for {2}", | ||
1371 | // CAPSULE_LENGTH, m_tainted_CAPSULE_LENGTH, Name); | ||
1372 | |||
1373 | m_pidControllerActive = true; | ||
1374 | |||
1375 | // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate() | ||
1376 | DestroyOdeStructures(); | ||
1377 | |||
1378 | float prevCapsule = CAPSULE_LENGTH; | ||
1379 | CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; | ||
1380 | |||
1381 | CreateOdeStructures( | ||
1382 | _position.X, | ||
1383 | _position.Y, | ||
1384 | _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor); | ||
1385 | |||
1386 | // As with Size, we reset velocity. However, this isn't strictly necessary since it doesn't | ||
1387 | // appear to stall initial region crossings when done here. Being done for consistency. | ||
1388 | // Velocity = Vector3.Zero; | ||
1389 | } | ||
1390 | else | ||
1391 | { | ||
1392 | m_log.Warn("[ODE CHARACTER]: trying to change capsule size for " + Name + ", but the following ODE data is missing - " | ||
1393 | + (Shell==IntPtr.Zero ? "Shell ":"") | ||
1394 | + (Body==IntPtr.Zero ? "Body ":"") | ||
1395 | + (Amotor==IntPtr.Zero ? "Amotor ":"")); | ||
1396 | } | ||
1397 | } | ||
1398 | } | ||
1399 | |||
1400 | internal void AddCollisionFrameTime(int p) | ||
1401 | { | ||
1402 | // protect it from overflow crashing | ||
1403 | if (m_eventsubscription + p >= int.MaxValue) | ||
1404 | m_eventsubscription = 0; | ||
1405 | m_eventsubscription += p; | ||
1406 | } | ||
1407 | } | ||
1408 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments new file mode 100644 index 0000000..1060aa6 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments | |||
@@ -0,0 +1,630 @@ | |||
1 | /* | ||
2 | * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
3 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
4 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
5 | * characteristics and Kinetic motion. | ||
6 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
7 | * (dynamics) and the associated settings. Old Linear and angular | ||
8 | * motors for dynamic motion have been replace with MoveLinear() | ||
9 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
10 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
11 | * switch between 'VEHICLE' parameter use and general dynamics | ||
12 | * settings use. | ||
13 | * | ||
14 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
15 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
16 | * | ||
17 | * Redistribution and use in source and binary forms, with or without | ||
18 | * modification, are permitted provided that the following conditions are met: | ||
19 | * * Redistributions of source code must retain the above copyright | ||
20 | * notice, this list of conditions and the following disclaimer. | ||
21 | * * Redistributions in binary form must reproduce the above copyright | ||
22 | * notice, this list of conditions and the following disclaimer in the | ||
23 | * documentation and/or other materials provided with the distribution. | ||
24 | * * Neither the name of the OpenSimulator Project nor the | ||
25 | * names of its contributors may be used to endorse or promote products | ||
26 | * derived from this software without specific prior written permission. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
29 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
30 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
31 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
32 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
33 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
34 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
35 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
36 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | using System; | ||
41 | using System.Collections.Generic; | ||
42 | using System.Reflection; | ||
43 | using System.Runtime.InteropServices; | ||
44 | using log4net; | ||
45 | using OpenMetaverse; | ||
46 | using Ode.NET; | ||
47 | using OpenSim.Framework; | ||
48 | using OpenSim.Region.Physics.Manager; | ||
49 | |||
50 | namespace OpenSim.Region.Physics.OdePlugin | ||
51 | { | ||
52 | public class ODEDynamics | ||
53 | { | ||
54 | public Vehicle Type | ||
55 | { | ||
56 | get { return m_type; } | ||
57 | } | ||
58 | |||
59 | public IntPtr Body | ||
60 | { | ||
61 | get { return m_body; } | ||
62 | } | ||
63 | |||
64 | private int frcount = 0; // Used to limit dynamics debug output to | ||
65 | // every 100th frame | ||
66 | |||
67 | // private OdeScene m_parentScene = null; | ||
68 | private IntPtr m_body = IntPtr.Zero; | ||
69 | private IntPtr m_jointGroup = IntPtr.Zero; | ||
70 | private IntPtr m_aMotor = IntPtr.Zero; | ||
71 | |||
72 | |||
73 | // Vehicle properties | ||
74 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind | ||
75 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier | ||
76 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: | ||
77 | // HOVER_TERRAIN_ONLY | ||
78 | // HOVER_GLOBAL_HEIGHT | ||
79 | // NO_DEFLECTION_UP | ||
80 | // HOVER_WATER_ONLY | ||
81 | // HOVER_UP_ONLY | ||
82 | // LIMIT_MOTOR_UP | ||
83 | // LIMIT_ROLL_ONLY | ||
84 | |||
85 | // Linear properties | ||
86 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | ||
87 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | ||
88 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body | ||
89 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | ||
90 | private float m_linearMotorDecayTimescale = 0; | ||
91 | private float m_linearMotorTimescale = 0; | ||
92 | private Vector3 m_lastLinearVelocityVector = Vector3.Zero; | ||
93 | // private bool m_LinearMotorSetLastFrame = false; | ||
94 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | ||
95 | |||
96 | //Angular properties | ||
97 | private Vector3 m_angularMotorDirection = Vector3.Zero; | ||
98 | private Vector3 m_angularMotorDirectionLASTSET = Vector3.Zero; | ||
99 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; | ||
100 | private float m_angularMotorDecayTimescale = 0; | ||
101 | private float m_angularMotorTimescale = 0; | ||
102 | private Vector3 m_lastAngularVelocityVector = Vector3.Zero; | ||
103 | |||
104 | //Deflection properties | ||
105 | // private float m_angularDeflectionEfficiency = 0; | ||
106 | // private float m_angularDeflectionTimescale = 0; | ||
107 | // private float m_linearDeflectionEfficiency = 0; | ||
108 | // private float m_linearDeflectionTimescale = 0; | ||
109 | |||
110 | //Banking properties | ||
111 | // private float m_bankingEfficiency = 0; | ||
112 | // private float m_bankingMix = 0; | ||
113 | // private float m_bankingTimescale = 0; | ||
114 | |||
115 | //Hover and Buoyancy properties | ||
116 | private float m_VhoverHeight = 0f; | ||
117 | private float m_VhoverEfficiency = 0f; | ||
118 | private float m_VhoverTimescale = 0f; | ||
119 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | ||
120 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. | ||
121 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | ||
122 | // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. | ||
123 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | ||
124 | |||
125 | //Attractor properties | ||
126 | private float m_verticalAttractionEfficiency = 0; | ||
127 | private float m_verticalAttractionTimescale = 0; | ||
128 | |||
129 | |||
130 | |||
131 | |||
132 | |||
133 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
134 | { | ||
135 | switch (pParam) | ||
136 | { | ||
137 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | ||
138 | if (pValue < 0.01f) pValue = 0.01f; | ||
139 | // m_angularDeflectionEfficiency = pValue; | ||
140 | break; | ||
141 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | ||
142 | if (pValue < 0.01f) pValue = 0.01f; | ||
143 | // m_angularDeflectionTimescale = pValue; | ||
144 | break; | ||
145 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | ||
146 | if (pValue < 0.01f) pValue = 0.01f; | ||
147 | m_angularMotorDecayTimescale = pValue; | ||
148 | break; | ||
149 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | ||
150 | if (pValue < 0.01f) pValue = 0.01f; | ||
151 | m_angularMotorTimescale = pValue; | ||
152 | break; | ||
153 | case Vehicle.BANKING_EFFICIENCY: | ||
154 | if (pValue < 0.01f) pValue = 0.01f; | ||
155 | // m_bankingEfficiency = pValue; | ||
156 | break; | ||
157 | case Vehicle.BANKING_MIX: | ||
158 | if (pValue < 0.01f) pValue = 0.01f; | ||
159 | // m_bankingMix = pValue; | ||
160 | break; | ||
161 | case Vehicle.BANKING_TIMESCALE: | ||
162 | if (pValue < 0.01f) pValue = 0.01f; | ||
163 | // m_bankingTimescale = pValue; | ||
164 | break; | ||
165 | case Vehicle.BUOYANCY: | ||
166 | if (pValue < -1f) pValue = -1f; | ||
167 | if (pValue > 1f) pValue = 1f; | ||
168 | m_VehicleBuoyancy = pValue; | ||
169 | break; | ||
170 | case Vehicle.HOVER_EFFICIENCY: | ||
171 | if (pValue < 0f) pValue = 0f; | ||
172 | if (pValue > 1f) pValue = 1f; | ||
173 | m_VhoverEfficiency = pValue; | ||
174 | break; | ||
175 | case Vehicle.HOVER_HEIGHT: | ||
176 | m_VhoverHeight = pValue; | ||
177 | break; | ||
178 | case Vehicle.HOVER_TIMESCALE: | ||
179 | if (pValue < 0.01f) pValue = 0.01f; | ||
180 | m_VhoverTimescale = pValue; | ||
181 | break; | ||
182 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | ||
183 | if (pValue < 0.01f) pValue = 0.01f; | ||
184 | // m_linearDeflectionEfficiency = pValue; | ||
185 | break; | ||
186 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | ||
187 | if (pValue < 0.01f) pValue = 0.01f; | ||
188 | // m_linearDeflectionTimescale = pValue; | ||
189 | break; | ||
190 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | ||
191 | if (pValue < 0.01f) pValue = 0.01f; | ||
192 | m_linearMotorDecayTimescale = pValue; | ||
193 | break; | ||
194 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | ||
195 | if (pValue < 0.01f) pValue = 0.01f; | ||
196 | m_linearMotorTimescale = pValue; | ||
197 | break; | ||
198 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | ||
199 | if (pValue < 0.0f) pValue = 0.0f; | ||
200 | if (pValue > 1.0f) pValue = 1.0f; | ||
201 | m_verticalAttractionEfficiency = pValue; | ||
202 | break; | ||
203 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | ||
204 | if (pValue < 0.01f) pValue = 0.01f; | ||
205 | m_verticalAttractionTimescale = pValue; | ||
206 | break; | ||
207 | |||
208 | // These are vector properties but the engine lets you use a single float value to | ||
209 | // set all of the components to the same value | ||
210 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
211 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
212 | break; | ||
213 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
214 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | ||
215 | m_angularMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | ||
216 | break; | ||
217 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
218 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
219 | break; | ||
220 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
221 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | ||
222 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | ||
223 | break; | ||
224 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
225 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | ||
226 | break; | ||
227 | |||
228 | } | ||
229 | |||
230 | }//end ProcessFloatVehicleParam | ||
231 | |||
232 | internal void ProcessVectorVehicleParam(Vehicle pParam, PhysicsVector pValue) | ||
233 | { | ||
234 | switch (pParam) | ||
235 | { | ||
236 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
237 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
238 | break; | ||
239 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
240 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
241 | m_angularMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
242 | break; | ||
243 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
244 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
245 | break; | ||
246 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
247 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
248 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
249 | break; | ||
250 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
251 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | }//end ProcessVectorVehicleParam | ||
256 | |||
257 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | ||
258 | { | ||
259 | switch (pParam) | ||
260 | { | ||
261 | case Vehicle.REFERENCE_FRAME: | ||
262 | // m_referenceFrame = pValue; | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | }//end ProcessRotationVehicleParam | ||
267 | |||
268 | internal void ProcessTypeChange(Vehicle pType) | ||
269 | { | ||
270 | Console.WriteLine("ProcessTypeChange to " + pType); | ||
271 | |||
272 | // Set Defaults For Type | ||
273 | m_type = pType; | ||
274 | switch (pType) | ||
275 | { | ||
276 | case Vehicle.TYPE_SLED: | ||
277 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
278 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
279 | m_linearMotorDirection = Vector3.Zero; | ||
280 | m_linearMotorTimescale = 1000; | ||
281 | m_linearMotorDecayTimescale = 120; | ||
282 | m_angularMotorDirection = Vector3.Zero; | ||
283 | m_angularMotorTimescale = 1000; | ||
284 | m_angularMotorDecayTimescale = 120; | ||
285 | m_VhoverHeight = 0; | ||
286 | m_VhoverEfficiency = 1; | ||
287 | m_VhoverTimescale = 10; | ||
288 | m_VehicleBuoyancy = 0; | ||
289 | // m_linearDeflectionEfficiency = 1; | ||
290 | // m_linearDeflectionTimescale = 1; | ||
291 | // m_angularDeflectionEfficiency = 1; | ||
292 | // m_angularDeflectionTimescale = 1000; | ||
293 | // m_bankingEfficiency = 0; | ||
294 | // m_bankingMix = 1; | ||
295 | // m_bankingTimescale = 10; | ||
296 | // m_referenceFrame = Quaternion.Identity; | ||
297 | m_flags &= | ||
298 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
299 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
300 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
301 | break; | ||
302 | case Vehicle.TYPE_CAR: | ||
303 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
304 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
305 | m_linearMotorDirection = Vector3.Zero; | ||
306 | m_linearMotorTimescale = 1; | ||
307 | m_linearMotorDecayTimescale = 60; | ||
308 | m_angularMotorDirection = Vector3.Zero; | ||
309 | m_angularMotorTimescale = 1; | ||
310 | m_angularMotorDecayTimescale = 0.8f; | ||
311 | m_VhoverHeight = 0; | ||
312 | m_VhoverEfficiency = 0; | ||
313 | m_VhoverTimescale = 1000; | ||
314 | m_VehicleBuoyancy = 0; | ||
315 | // // m_linearDeflectionEfficiency = 1; | ||
316 | // // m_linearDeflectionTimescale = 2; | ||
317 | // // m_angularDeflectionEfficiency = 0; | ||
318 | // m_angularDeflectionTimescale = 10; | ||
319 | m_verticalAttractionEfficiency = 1; | ||
320 | m_verticalAttractionTimescale = 10; | ||
321 | // m_bankingEfficiency = -0.2f; | ||
322 | // m_bankingMix = 1; | ||
323 | // m_bankingTimescale = 1; | ||
324 | // m_referenceFrame = Quaternion.Identity; | ||
325 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
326 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY | | ||
327 | VehicleFlag.LIMIT_MOTOR_UP); | ||
328 | break; | ||
329 | case Vehicle.TYPE_BOAT: | ||
330 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
331 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
332 | m_linearMotorDirection = Vector3.Zero; | ||
333 | m_linearMotorTimescale = 5; | ||
334 | m_linearMotorDecayTimescale = 60; | ||
335 | m_angularMotorDirection = Vector3.Zero; | ||
336 | m_angularMotorTimescale = 4; | ||
337 | m_angularMotorDecayTimescale = 4; | ||
338 | m_VhoverHeight = 0; | ||
339 | m_VhoverEfficiency = 0.5f; | ||
340 | m_VhoverTimescale = 2; | ||
341 | m_VehicleBuoyancy = 1; | ||
342 | // m_linearDeflectionEfficiency = 0.5f; | ||
343 | // m_linearDeflectionTimescale = 3; | ||
344 | // m_angularDeflectionEfficiency = 0.5f; | ||
345 | // m_angularDeflectionTimescale = 5; | ||
346 | m_verticalAttractionEfficiency = 0.5f; | ||
347 | m_verticalAttractionTimescale = 5; | ||
348 | // m_bankingEfficiency = -0.3f; | ||
349 | // m_bankingMix = 0.8f; | ||
350 | // m_bankingTimescale = 1; | ||
351 | // m_referenceFrame = Quaternion.Identity; | ||
352 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY | | ||
353 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
354 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | | ||
355 | VehicleFlag.LIMIT_MOTOR_UP); | ||
356 | break; | ||
357 | case Vehicle.TYPE_AIRPLANE: | ||
358 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
359 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
360 | m_linearMotorDirection = Vector3.Zero; | ||
361 | m_linearMotorTimescale = 2; | ||
362 | m_linearMotorDecayTimescale = 60; | ||
363 | m_angularMotorDirection = Vector3.Zero; | ||
364 | m_angularMotorTimescale = 4; | ||
365 | m_angularMotorDecayTimescale = 4; | ||
366 | m_VhoverHeight = 0; | ||
367 | m_VhoverEfficiency = 0.5f; | ||
368 | m_VhoverTimescale = 1000; | ||
369 | m_VehicleBuoyancy = 0; | ||
370 | // m_linearDeflectionEfficiency = 0.5f; | ||
371 | // m_linearDeflectionTimescale = 3; | ||
372 | // m_angularDeflectionEfficiency = 1; | ||
373 | // m_angularDeflectionTimescale = 2; | ||
374 | m_verticalAttractionEfficiency = 0.9f; | ||
375 | m_verticalAttractionTimescale = 2; | ||
376 | // m_bankingEfficiency = 1; | ||
377 | // m_bankingMix = 0.7f; | ||
378 | // m_bankingTimescale = 2; | ||
379 | // m_referenceFrame = Quaternion.Identity; | ||
380 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
381 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
382 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
383 | break; | ||
384 | case Vehicle.TYPE_BALLOON: | ||
385 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
386 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
387 | m_linearMotorDirection = Vector3.Zero; | ||
388 | m_linearMotorTimescale = 5; | ||
389 | m_linearMotorDecayTimescale = 60; | ||
390 | m_angularMotorDirection = Vector3.Zero; | ||
391 | m_angularMotorTimescale = 6; | ||
392 | m_angularMotorDecayTimescale = 10; | ||
393 | m_VhoverHeight = 5; | ||
394 | m_VhoverEfficiency = 0.8f; | ||
395 | m_VhoverTimescale = 10; | ||
396 | m_VehicleBuoyancy = 1; | ||
397 | // m_linearDeflectionEfficiency = 0; | ||
398 | // m_linearDeflectionTimescale = 5; | ||
399 | // m_angularDeflectionEfficiency = 0; | ||
400 | // m_angularDeflectionTimescale = 5; | ||
401 | m_verticalAttractionEfficiency = 1; | ||
402 | m_verticalAttractionTimescale = 1000; | ||
403 | // m_bankingEfficiency = 0; | ||
404 | // m_bankingMix = 0.7f; | ||
405 | // m_bankingTimescale = 5; | ||
406 | // m_referenceFrame = Quaternion.Identity; | ||
407 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
408 | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
409 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
410 | break; | ||
411 | |||
412 | } | ||
413 | }//end SetDefaultsForType | ||
414 | |||
415 | internal void Enable(IntPtr pBody, OdeScene pParentScene) | ||
416 | { | ||
417 | //Console.WriteLine("Enable m_type=" + m_type + " m_VehicleBuoyancy=" + m_VehicleBuoyancy); | ||
418 | if (m_type == Vehicle.TYPE_NONE) | ||
419 | return; | ||
420 | |||
421 | m_body = pBody; | ||
422 | //KF: This used to set up the linear and angular joints | ||
423 | } | ||
424 | |||
425 | internal void Step(float pTimestep, OdeScene pParentScene) | ||
426 | { | ||
427 | if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) | ||
428 | return; | ||
429 | frcount++; // used to limit debug comment output | ||
430 | if (frcount > 100) | ||
431 | frcount = 0; | ||
432 | |||
433 | MoveLinear(pTimestep, pParentScene); | ||
434 | MoveAngular(pTimestep); | ||
435 | }// end Step | ||
436 | |||
437 | private void MoveLinear(float pTimestep, OdeScene _pParentScene) | ||
438 | { | ||
439 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant | ||
440 | { | ||
441 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | ||
442 | |||
443 | // add drive to body | ||
444 | Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); | ||
445 | m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? | ||
446 | |||
447 | // This will work temporarily, but we really need to compare speed on an axis | ||
448 | // KF: Limit body velocity to applied velocity? | ||
449 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | ||
450 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | ||
451 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | ||
452 | m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; | ||
453 | if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) | ||
454 | m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; | ||
455 | |||
456 | // decay applied velocity | ||
457 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | ||
458 | //Console.WriteLine("decay: " + decayfraction); | ||
459 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction; | ||
460 | //Console.WriteLine("actual: " + m_linearMotorDirection); | ||
461 | } | ||
462 | else | ||
463 | { // requested is not significant | ||
464 | // if what remains of applied is small, zero it. | ||
465 | if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) | ||
466 | m_lastLinearVelocityVector = Vector3.Zero; | ||
467 | } | ||
468 | |||
469 | |||
470 | // convert requested object velocity to world-referenced vector | ||
471 | m_dir = m_lastLinearVelocityVector; | ||
472 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
473 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object | ||
474 | m_dir *= rotq; // apply obj rotation to velocity vector | ||
475 | |||
476 | // add Gravity andBuoyancy | ||
477 | // KF: So far I have found no good method to combine a script-requested | ||
478 | // .Z velocity and gravity. Therefore only 0g will used script-requested | ||
479 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. | ||
480 | Vector3 grav = Vector3.Zero; | ||
481 | if(m_VehicleBuoyancy < 1.0f) | ||
482 | { | ||
483 | // There is some gravity, make a gravity force vector | ||
484 | // that is applied after object velocity. | ||
485 | d.Mass objMass; | ||
486 | d.BodyGetMass(Body, out objMass); | ||
487 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
488 | grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); | ||
489 | // Preserve the current Z velocity | ||
490 | d.Vector3 vel_now = d.BodyGetLinearVel(Body); | ||
491 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | ||
492 | } // else its 1.0, no gravity. | ||
493 | |||
494 | // Check if hovering | ||
495 | if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | ||
496 | { | ||
497 | // We should hover, get the target height | ||
498 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
499 | if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY) | ||
500 | { | ||
501 | m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; | ||
502 | } | ||
503 | else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY) | ||
504 | { | ||
505 | m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; | ||
506 | } | ||
507 | else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT) | ||
508 | { | ||
509 | m_VhoverTargetHeight = m_VhoverHeight; | ||
510 | } | ||
511 | |||
512 | if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY) | ||
513 | { | ||
514 | // If body is aready heigher, use its height as target height | ||
515 | if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; | ||
516 | } | ||
517 | |||
518 | // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped | ||
519 | // m_VhoverTimescale = 0f; // time to acheive height | ||
520 | // pTimestep is time since last frame,in secs | ||
521 | float herr0 = pos.Z - m_VhoverTargetHeight; | ||
522 | //if(frcount == 0) Console.WriteLine("herr0=" + herr0); | ||
523 | // Replace Vertical speed with correction figure if significant | ||
524 | if(Math.Abs(herr0) > 0.01f ) | ||
525 | { | ||
526 | d.Mass objMass; | ||
527 | d.BodyGetMass(Body, out objMass); | ||
528 | m_dir.Z = - ( (herr0 * pTimestep * 50.0f) / m_VhoverTimescale); | ||
529 | // m_VhoverEfficiency is not yet implemented | ||
530 | } | ||
531 | else | ||
532 | { | ||
533 | m_dir.Z = 0f; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | // Apply velocity | ||
538 | d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); | ||
539 | //if(frcount == 0) Console.WriteLine("Move " + Body + ":"+ m_dir.X + " " + m_dir.Y + " " + m_dir.Z); | ||
540 | // apply gravity force | ||
541 | d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); | ||
542 | //if(frcount == 0) Console.WriteLine("Force " + Body + ":" + grav.X + " " + grav.Y + " " + grav.Z); | ||
543 | |||
544 | |||
545 | // apply friction | ||
546 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); | ||
547 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; | ||
548 | } // end MoveLinear() | ||
549 | |||
550 | private void MoveAngular(float pTimestep) | ||
551 | { | ||
552 | |||
553 | // m_angularMotorDirection is the latest value from the script, and is decayed here | ||
554 | // m_angularMotorDirectionLASTSET is the latest value from the script | ||
555 | // m_lastAngularVelocityVector is what is being applied to the Body, varied up and down here | ||
556 | |||
557 | if (!m_angularMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) | ||
558 | { | ||
559 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | ||
560 | // ramp up to new value | ||
561 | Vector3 addAmount = m_angularMotorDirection / (m_angularMotorTimescale / pTimestep); | ||
562 | m_lastAngularVelocityVector += (addAmount * 10f); | ||
563 | //if(frcount == 0) Console.WriteLine("add: " + addAmount); | ||
564 | |||
565 | // limit applied value to what was set by script | ||
566 | // This will work temporarily, but we really need to compare speed on an axis | ||
567 | if (Math.Abs(m_lastAngularVelocityVector.X) > Math.Abs(m_angularMotorDirectionLASTSET.X)) | ||
568 | m_lastAngularVelocityVector.X = m_angularMotorDirectionLASTSET.X; | ||
569 | if (Math.Abs(m_lastAngularVelocityVector.Y) > Math.Abs(m_angularMotorDirectionLASTSET.Y)) | ||
570 | m_lastAngularVelocityVector.Y = m_angularMotorDirectionLASTSET.Y; | ||
571 | if (Math.Abs(m_lastAngularVelocityVector.Z) > Math.Abs(m_angularMotorDirectionLASTSET.Z)) | ||
572 | m_lastAngularVelocityVector.Z = m_angularMotorDirectionLASTSET.Z; | ||
573 | |||
574 | // decay the requested value | ||
575 | Vector3 decayfraction = ((Vector3.One / (m_angularMotorDecayTimescale / pTimestep))); | ||
576 | //Console.WriteLine("decay: " + decayfraction); | ||
577 | m_angularMotorDirection -= m_angularMotorDirection * decayfraction; | ||
578 | //Console.WriteLine("actual: " + m_linearMotorDirection); | ||
579 | } | ||
580 | // KF: m_lastAngularVelocityVector is rotational speed in rad/sec ? | ||
581 | |||
582 | // Vertical attractor section | ||
583 | |||
584 | // d.Mass objMass; | ||
585 | // d.BodyGetMass(Body, out objMass); | ||
586 | // float servo = 100f * objMass.mass * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep); | ||
587 | float servo = 0.1f * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep); | ||
588 | // get present body rotation | ||
589 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
590 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); | ||
591 | // make a vector pointing up | ||
592 | Vector3 verterr = Vector3.Zero; | ||
593 | verterr.Z = 1.0f; | ||
594 | // rotate it to Body Angle | ||
595 | verterr = verterr * rotq; | ||
596 | // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. | ||
597 | // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go | ||
598 | // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. | ||
599 | if (verterr.Z < 0.0f) | ||
600 | { | ||
601 | verterr.X = 2.0f - verterr.X; | ||
602 | verterr.Y = 2.0f - verterr.Y; | ||
603 | } | ||
604 | // Error is 0 (no error) to +/- 2 (max error) | ||
605 | // scale it by servo | ||
606 | verterr = verterr * servo; | ||
607 | |||
608 | // rotate to object frame | ||
609 | // verterr = verterr * rotq; | ||
610 | |||
611 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so | ||
612 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. | ||
613 | m_lastAngularVelocityVector.X += verterr.Y; | ||
614 | m_lastAngularVelocityVector.Y -= verterr.X; | ||
615 | /* | ||
616 | if(frcount == 0) | ||
617 | { | ||
618 | // Console.WriteLine("AngleMotor " + m_lastAngularVelocityVector); | ||
619 | Console.WriteLine(String.Format("VA Body:{0} servo:{1} err:<{2},{3},{4}> VAE:{5}", | ||
620 | Body, servo, verterr.X, verterr.Y, verterr.Z, m_verticalAttractionEfficiency)); | ||
621 | } | ||
622 | */ | ||
623 | d.BodySetAngularVel (Body, m_lastAngularVelocityVector.X, m_lastAngularVelocityVector.Y, m_lastAngularVelocityVector.Z); | ||
624 | // apply friction | ||
625 | Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); | ||
626 | m_lastAngularVelocityVector -= m_lastAngularVelocityVector * decayamount; | ||
627 | |||
628 | } //end MoveAngular | ||
629 | } | ||
630 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs new file mode 100644 index 0000000..7e95d7f --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs | |||
@@ -0,0 +1,981 @@ | |||
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 | /* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
29 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
30 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
31 | * characteristics and Kinetic motion. | ||
32 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
33 | * (dynamics) and the associated settings. Old Linear and angular | ||
34 | * motors for dynamic motion have been replace with MoveLinear() | ||
35 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
36 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
37 | * switch between 'VEHICLE' parameter use and general dynamics | ||
38 | * settings use. | ||
39 | */ | ||
40 | |||
41 | using System; | ||
42 | using System.Collections.Generic; | ||
43 | using System.Reflection; | ||
44 | using System.Runtime.InteropServices; | ||
45 | using log4net; | ||
46 | using OpenMetaverse; | ||
47 | using OpenSim.Framework; | ||
48 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
49 | |||
50 | |||
51 | namespace OpenSim.Region.PhysicsModule.ODE | ||
52 | { | ||
53 | public class ODEDynamics | ||
54 | { | ||
55 | public Vehicle Type | ||
56 | { | ||
57 | get { return m_type; } | ||
58 | } | ||
59 | |||
60 | public IntPtr Body | ||
61 | { | ||
62 | get { return m_body; } | ||
63 | } | ||
64 | |||
65 | private int frcount = 0; // Used to limit dynamics debug output to | ||
66 | // every 100th frame | ||
67 | |||
68 | // private OdeScene m_parentScene = null; | ||
69 | private IntPtr m_body = IntPtr.Zero; | ||
70 | // private IntPtr m_jointGroup = IntPtr.Zero; | ||
71 | // private IntPtr m_aMotor = IntPtr.Zero; | ||
72 | |||
73 | |||
74 | // Vehicle properties | ||
75 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind | ||
76 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier | ||
77 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: | ||
78 | // HOVER_TERRAIN_ONLY | ||
79 | // HOVER_GLOBAL_HEIGHT | ||
80 | // NO_DEFLECTION_UP | ||
81 | // HOVER_WATER_ONLY | ||
82 | // HOVER_UP_ONLY | ||
83 | // LIMIT_MOTOR_UP | ||
84 | // LIMIT_ROLL_ONLY | ||
85 | private VehicleFlag m_Hoverflags = (VehicleFlag)0; | ||
86 | private Vector3 m_BlockingEndPoint = Vector3.Zero; | ||
87 | private Quaternion m_RollreferenceFrame = Quaternion.Identity; | ||
88 | // Linear properties | ||
89 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | ||
90 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | ||
91 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body | ||
92 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | ||
93 | private float m_linearMotorDecayTimescale = 0; | ||
94 | private float m_linearMotorTimescale = 0; | ||
95 | private Vector3 m_lastLinearVelocityVector = Vector3.Zero; | ||
96 | private d.Vector3 m_lastPositionVector = new d.Vector3(); | ||
97 | // private bool m_LinearMotorSetLastFrame = false; | ||
98 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | ||
99 | |||
100 | //Angular properties | ||
101 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | ||
102 | private int m_angularMotorApply = 0; // application frame counter | ||
103 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | ||
104 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | ||
105 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | ||
106 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | ||
107 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | ||
108 | // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | ||
109 | |||
110 | //Deflection properties | ||
111 | // private float m_angularDeflectionEfficiency = 0; | ||
112 | // private float m_angularDeflectionTimescale = 0; | ||
113 | // private float m_linearDeflectionEfficiency = 0; | ||
114 | // private float m_linearDeflectionTimescale = 0; | ||
115 | |||
116 | //Banking properties | ||
117 | // private float m_bankingEfficiency = 0; | ||
118 | // private float m_bankingMix = 0; | ||
119 | // private float m_bankingTimescale = 0; | ||
120 | |||
121 | //Hover and Buoyancy properties | ||
122 | private float m_VhoverHeight = 0f; | ||
123 | // private float m_VhoverEfficiency = 0f; | ||
124 | private float m_VhoverTimescale = 0f; | ||
125 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | ||
126 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. | ||
127 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | ||
128 | // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. | ||
129 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | ||
130 | |||
131 | //Attractor properties | ||
132 | private float m_verticalAttractionEfficiency = 1.0f; // damped | ||
133 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | ||
134 | |||
135 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
136 | { | ||
137 | switch (pParam) | ||
138 | { | ||
139 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | ||
140 | if (pValue < 0.01f) pValue = 0.01f; | ||
141 | // m_angularDeflectionEfficiency = pValue; | ||
142 | break; | ||
143 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | ||
144 | if (pValue < 0.01f) pValue = 0.01f; | ||
145 | // m_angularDeflectionTimescale = pValue; | ||
146 | break; | ||
147 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | ||
148 | if (pValue < 0.01f) pValue = 0.01f; | ||
149 | m_angularMotorDecayTimescale = pValue; | ||
150 | break; | ||
151 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | ||
152 | if (pValue < 0.01f) pValue = 0.01f; | ||
153 | m_angularMotorTimescale = pValue; | ||
154 | break; | ||
155 | case Vehicle.BANKING_EFFICIENCY: | ||
156 | if (pValue < 0.01f) pValue = 0.01f; | ||
157 | // m_bankingEfficiency = pValue; | ||
158 | break; | ||
159 | case Vehicle.BANKING_MIX: | ||
160 | if (pValue < 0.01f) pValue = 0.01f; | ||
161 | // m_bankingMix = pValue; | ||
162 | break; | ||
163 | case Vehicle.BANKING_TIMESCALE: | ||
164 | if (pValue < 0.01f) pValue = 0.01f; | ||
165 | // m_bankingTimescale = pValue; | ||
166 | break; | ||
167 | case Vehicle.BUOYANCY: | ||
168 | if (pValue < -1f) pValue = -1f; | ||
169 | if (pValue > 1f) pValue = 1f; | ||
170 | m_VehicleBuoyancy = pValue; | ||
171 | break; | ||
172 | // case Vehicle.HOVER_EFFICIENCY: | ||
173 | // if (pValue < 0f) pValue = 0f; | ||
174 | // if (pValue > 1f) pValue = 1f; | ||
175 | // m_VhoverEfficiency = pValue; | ||
176 | // break; | ||
177 | case Vehicle.HOVER_HEIGHT: | ||
178 | m_VhoverHeight = pValue; | ||
179 | break; | ||
180 | case Vehicle.HOVER_TIMESCALE: | ||
181 | if (pValue < 0.01f) pValue = 0.01f; | ||
182 | m_VhoverTimescale = pValue; | ||
183 | break; | ||
184 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | ||
185 | if (pValue < 0.01f) pValue = 0.01f; | ||
186 | // m_linearDeflectionEfficiency = pValue; | ||
187 | break; | ||
188 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | ||
189 | if (pValue < 0.01f) pValue = 0.01f; | ||
190 | // m_linearDeflectionTimescale = pValue; | ||
191 | break; | ||
192 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | ||
193 | if (pValue < 0.01f) pValue = 0.01f; | ||
194 | m_linearMotorDecayTimescale = pValue; | ||
195 | break; | ||
196 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | ||
197 | if (pValue < 0.01f) pValue = 0.01f; | ||
198 | m_linearMotorTimescale = pValue; | ||
199 | break; | ||
200 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | ||
201 | if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable | ||
202 | if (pValue > 1.0f) pValue = 1.0f; | ||
203 | m_verticalAttractionEfficiency = pValue; | ||
204 | break; | ||
205 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | ||
206 | if (pValue < 0.01f) pValue = 0.01f; | ||
207 | m_verticalAttractionTimescale = pValue; | ||
208 | break; | ||
209 | |||
210 | // These are vector properties but the engine lets you use a single float value to | ||
211 | // set all of the components to the same value | ||
212 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
213 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
214 | break; | ||
215 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
216 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | ||
217 | m_angularMotorApply = 10; | ||
218 | break; | ||
219 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
220 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
221 | break; | ||
222 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
223 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | ||
224 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | ||
225 | break; | ||
226 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
227 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | ||
228 | break; | ||
229 | |||
230 | } | ||
231 | }//end ProcessFloatVehicleParam | ||
232 | |||
233 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | ||
234 | { | ||
235 | switch (pParam) | ||
236 | { | ||
237 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
238 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
239 | break; | ||
240 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
241 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
242 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | ||
243 | if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; | ||
244 | if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; | ||
245 | if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; | ||
246 | if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; | ||
247 | if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; | ||
248 | if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f; | ||
249 | m_angularMotorApply = 10; | ||
250 | break; | ||
251 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
252 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
253 | break; | ||
254 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
255 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
256 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
257 | break; | ||
258 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
259 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
260 | break; | ||
261 | case Vehicle.BLOCK_EXIT: | ||
262 | m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
263 | break; | ||
264 | } | ||
265 | }//end ProcessVectorVehicleParam | ||
266 | |||
267 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | ||
268 | { | ||
269 | switch (pParam) | ||
270 | { | ||
271 | case Vehicle.REFERENCE_FRAME: | ||
272 | // m_referenceFrame = pValue; | ||
273 | break; | ||
274 | case Vehicle.ROLL_FRAME: | ||
275 | m_RollreferenceFrame = pValue; | ||
276 | break; | ||
277 | } | ||
278 | }//end ProcessRotationVehicleParam | ||
279 | |||
280 | internal void ProcessVehicleFlags(int pParam, bool remove) | ||
281 | { | ||
282 | if (remove) | ||
283 | { | ||
284 | if (pParam == -1) | ||
285 | { | ||
286 | m_flags = (VehicleFlag)0; | ||
287 | m_Hoverflags = (VehicleFlag)0; | ||
288 | return; | ||
289 | } | ||
290 | if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) | ||
291 | { | ||
292 | if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0) | ||
293 | m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
294 | } | ||
295 | if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) | ||
296 | { | ||
297 | if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0) | ||
298 | m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY); | ||
299 | } | ||
300 | if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) | ||
301 | { | ||
302 | if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0) | ||
303 | m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY); | ||
304 | } | ||
305 | if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) | ||
306 | { | ||
307 | if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0) | ||
308 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY); | ||
309 | } | ||
310 | if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) | ||
311 | { | ||
312 | if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0) | ||
313 | m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP); | ||
314 | } | ||
315 | if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY) | ||
316 | { | ||
317 | if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0) | ||
318 | m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); | ||
319 | } | ||
320 | if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) | ||
321 | { | ||
322 | if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0) | ||
323 | m_flags &= ~(VehicleFlag.MOUSELOOK_BANK); | ||
324 | } | ||
325 | if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) | ||
326 | { | ||
327 | if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0) | ||
328 | m_flags &= ~(VehicleFlag.MOUSELOOK_STEER); | ||
329 | } | ||
330 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) | ||
331 | { | ||
332 | if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0) | ||
333 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP); | ||
334 | } | ||
335 | if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) | ||
336 | { | ||
337 | if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0) | ||
338 | m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED); | ||
339 | } | ||
340 | if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) | ||
341 | { | ||
342 | if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0) | ||
343 | m_flags &= ~(VehicleFlag.NO_X); | ||
344 | } | ||
345 | if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) | ||
346 | { | ||
347 | if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0) | ||
348 | m_flags &= ~(VehicleFlag.NO_Y); | ||
349 | } | ||
350 | if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) | ||
351 | { | ||
352 | if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0) | ||
353 | m_flags &= ~(VehicleFlag.NO_Z); | ||
354 | } | ||
355 | if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) | ||
356 | { | ||
357 | if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0) | ||
358 | m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT); | ||
359 | } | ||
360 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) | ||
361 | { | ||
362 | if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0) | ||
363 | m_flags &= ~(VehicleFlag.NO_DEFLECTION); | ||
364 | } | ||
365 | if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) | ||
366 | { | ||
367 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0) | ||
368 | m_flags &= ~(VehicleFlag.LOCK_ROTATION); | ||
369 | } | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) | ||
374 | { | ||
375 | m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags); | ||
376 | } | ||
377 | if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) | ||
378 | { | ||
379 | m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags); | ||
380 | } | ||
381 | if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) | ||
382 | { | ||
383 | m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags); | ||
384 | } | ||
385 | if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) | ||
386 | { | ||
387 | m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags); | ||
388 | } | ||
389 | if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) | ||
390 | { | ||
391 | m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags); | ||
392 | } | ||
393 | if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) | ||
394 | { | ||
395 | m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags); | ||
396 | } | ||
397 | if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) | ||
398 | { | ||
399 | m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags); | ||
400 | } | ||
401 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) | ||
402 | { | ||
403 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags); | ||
404 | } | ||
405 | if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) | ||
406 | { | ||
407 | m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags); | ||
408 | } | ||
409 | if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) | ||
410 | { | ||
411 | m_flags |= (VehicleFlag.NO_X); | ||
412 | } | ||
413 | if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) | ||
414 | { | ||
415 | m_flags |= (VehicleFlag.NO_Y); | ||
416 | } | ||
417 | if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) | ||
418 | { | ||
419 | m_flags |= (VehicleFlag.NO_Z); | ||
420 | } | ||
421 | if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) | ||
422 | { | ||
423 | m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT); | ||
424 | } | ||
425 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) | ||
426 | { | ||
427 | m_flags |= (VehicleFlag.NO_DEFLECTION); | ||
428 | } | ||
429 | if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) | ||
430 | { | ||
431 | m_flags |= (VehicleFlag.LOCK_ROTATION); | ||
432 | } | ||
433 | } | ||
434 | }//end ProcessVehicleFlags | ||
435 | |||
436 | internal void ProcessTypeChange(Vehicle pType) | ||
437 | { | ||
438 | // Set Defaults For Type | ||
439 | m_type = pType; | ||
440 | switch (pType) | ||
441 | { | ||
442 | case Vehicle.TYPE_NONE: | ||
443 | m_linearFrictionTimescale = new Vector3(0, 0, 0); | ||
444 | m_angularFrictionTimescale = new Vector3(0, 0, 0); | ||
445 | m_linearMotorDirection = Vector3.Zero; | ||
446 | m_linearMotorTimescale = 0; | ||
447 | m_linearMotorDecayTimescale = 0; | ||
448 | m_angularMotorDirection = Vector3.Zero; | ||
449 | m_angularMotorTimescale = 0; | ||
450 | m_angularMotorDecayTimescale = 0; | ||
451 | m_VhoverHeight = 0; | ||
452 | m_VhoverTimescale = 0; | ||
453 | m_VehicleBuoyancy = 0; | ||
454 | m_flags = (VehicleFlag)0; | ||
455 | break; | ||
456 | |||
457 | case Vehicle.TYPE_SLED: | ||
458 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
459 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
460 | m_linearMotorDirection = Vector3.Zero; | ||
461 | m_linearMotorTimescale = 1000; | ||
462 | m_linearMotorDecayTimescale = 120; | ||
463 | m_angularMotorDirection = Vector3.Zero; | ||
464 | m_angularMotorTimescale = 1000; | ||
465 | m_angularMotorDecayTimescale = 120; | ||
466 | m_VhoverHeight = 0; | ||
467 | // m_VhoverEfficiency = 1; | ||
468 | m_VhoverTimescale = 10; | ||
469 | m_VehicleBuoyancy = 0; | ||
470 | // m_linearDeflectionEfficiency = 1; | ||
471 | // m_linearDeflectionTimescale = 1; | ||
472 | // m_angularDeflectionEfficiency = 1; | ||
473 | // m_angularDeflectionTimescale = 1000; | ||
474 | // m_bankingEfficiency = 0; | ||
475 | // m_bankingMix = 1; | ||
476 | // m_bankingTimescale = 10; | ||
477 | // m_referenceFrame = Quaternion.Identity; | ||
478 | m_Hoverflags &= | ||
479 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
480 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
481 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
482 | break; | ||
483 | case Vehicle.TYPE_CAR: | ||
484 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
485 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
486 | m_linearMotorDirection = Vector3.Zero; | ||
487 | m_linearMotorTimescale = 1; | ||
488 | m_linearMotorDecayTimescale = 60; | ||
489 | m_angularMotorDirection = Vector3.Zero; | ||
490 | m_angularMotorTimescale = 1; | ||
491 | m_angularMotorDecayTimescale = 0.8f; | ||
492 | m_VhoverHeight = 0; | ||
493 | // m_VhoverEfficiency = 0; | ||
494 | m_VhoverTimescale = 1000; | ||
495 | m_VehicleBuoyancy = 0; | ||
496 | // // m_linearDeflectionEfficiency = 1; | ||
497 | // // m_linearDeflectionTimescale = 2; | ||
498 | // // m_angularDeflectionEfficiency = 0; | ||
499 | // m_angularDeflectionTimescale = 10; | ||
500 | m_verticalAttractionEfficiency = 1f; | ||
501 | m_verticalAttractionTimescale = 10f; | ||
502 | // m_bankingEfficiency = -0.2f; | ||
503 | // m_bankingMix = 1; | ||
504 | // m_bankingTimescale = 1; | ||
505 | // m_referenceFrame = Quaternion.Identity; | ||
506 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
507 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | | ||
508 | VehicleFlag.LIMIT_MOTOR_UP); | ||
509 | m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY); | ||
510 | break; | ||
511 | case Vehicle.TYPE_BOAT: | ||
512 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
513 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
514 | m_linearMotorDirection = Vector3.Zero; | ||
515 | m_linearMotorTimescale = 5; | ||
516 | m_linearMotorDecayTimescale = 60; | ||
517 | m_angularMotorDirection = Vector3.Zero; | ||
518 | m_angularMotorTimescale = 4; | ||
519 | m_angularMotorDecayTimescale = 4; | ||
520 | m_VhoverHeight = 0; | ||
521 | // m_VhoverEfficiency = 0.5f; | ||
522 | m_VhoverTimescale = 2; | ||
523 | m_VehicleBuoyancy = 1; | ||
524 | // m_linearDeflectionEfficiency = 0.5f; | ||
525 | // m_linearDeflectionTimescale = 3; | ||
526 | // m_angularDeflectionEfficiency = 0.5f; | ||
527 | // m_angularDeflectionTimescale = 5; | ||
528 | m_verticalAttractionEfficiency = 0.5f; | ||
529 | m_verticalAttractionTimescale = 5f; | ||
530 | // m_bankingEfficiency = -0.3f; | ||
531 | // m_bankingMix = 0.8f; | ||
532 | // m_bankingTimescale = 1; | ||
533 | // m_referenceFrame = Quaternion.Identity; | ||
534 | m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | | ||
535 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
536 | m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); | ||
537 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | | ||
538 | VehicleFlag.LIMIT_MOTOR_UP); | ||
539 | m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY); | ||
540 | break; | ||
541 | case Vehicle.TYPE_AIRPLANE: | ||
542 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
543 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
544 | m_linearMotorDirection = Vector3.Zero; | ||
545 | m_linearMotorTimescale = 2; | ||
546 | m_linearMotorDecayTimescale = 60; | ||
547 | m_angularMotorDirection = Vector3.Zero; | ||
548 | m_angularMotorTimescale = 4; | ||
549 | m_angularMotorDecayTimescale = 4; | ||
550 | m_VhoverHeight = 0; | ||
551 | // m_VhoverEfficiency = 0.5f; | ||
552 | m_VhoverTimescale = 1000; | ||
553 | m_VehicleBuoyancy = 0; | ||
554 | // m_linearDeflectionEfficiency = 0.5f; | ||
555 | // m_linearDeflectionTimescale = 3; | ||
556 | // m_angularDeflectionEfficiency = 1; | ||
557 | // m_angularDeflectionTimescale = 2; | ||
558 | m_verticalAttractionEfficiency = 0.9f; | ||
559 | m_verticalAttractionTimescale = 2f; | ||
560 | // m_bankingEfficiency = 1; | ||
561 | // m_bankingMix = 0.7f; | ||
562 | // m_bankingTimescale = 2; | ||
563 | // m_referenceFrame = Quaternion.Identity; | ||
564 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
565 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
566 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); | ||
567 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
568 | break; | ||
569 | case Vehicle.TYPE_BALLOON: | ||
570 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
571 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
572 | m_linearMotorDirection = Vector3.Zero; | ||
573 | m_linearMotorTimescale = 5; | ||
574 | m_linearMotorDecayTimescale = 60; | ||
575 | m_angularMotorDirection = Vector3.Zero; | ||
576 | m_angularMotorTimescale = 6; | ||
577 | m_angularMotorDecayTimescale = 10; | ||
578 | m_VhoverHeight = 5; | ||
579 | // m_VhoverEfficiency = 0.8f; | ||
580 | m_VhoverTimescale = 10; | ||
581 | m_VehicleBuoyancy = 1; | ||
582 | // m_linearDeflectionEfficiency = 0; | ||
583 | // m_linearDeflectionTimescale = 5; | ||
584 | // m_angularDeflectionEfficiency = 0; | ||
585 | // m_angularDeflectionTimescale = 5; | ||
586 | m_verticalAttractionEfficiency = 1f; | ||
587 | m_verticalAttractionTimescale = 100f; | ||
588 | // m_bankingEfficiency = 0; | ||
589 | // m_bankingMix = 0.7f; | ||
590 | // m_bankingTimescale = 5; | ||
591 | // m_referenceFrame = Quaternion.Identity; | ||
592 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
593 | VehicleFlag.HOVER_UP_ONLY); | ||
594 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); | ||
595 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
596 | m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
597 | break; | ||
598 | |||
599 | } | ||
600 | }//end SetDefaultsForType | ||
601 | |||
602 | internal void Enable(IntPtr pBody, OdeScene pParentScene) | ||
603 | { | ||
604 | if (m_type == Vehicle.TYPE_NONE) | ||
605 | return; | ||
606 | |||
607 | m_body = pBody; | ||
608 | } | ||
609 | |||
610 | internal void Stop() | ||
611 | { | ||
612 | m_lastLinearVelocityVector = Vector3.Zero; | ||
613 | m_lastAngularVelocity = Vector3.Zero; | ||
614 | m_lastPositionVector = d.BodyGetPosition(Body); | ||
615 | } | ||
616 | |||
617 | internal void Step(float pTimestep, OdeScene pParentScene) | ||
618 | { | ||
619 | if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) | ||
620 | return; | ||
621 | frcount++; // used to limit debug comment output | ||
622 | if (frcount > 100) | ||
623 | frcount = 0; | ||
624 | |||
625 | MoveLinear(pTimestep, pParentScene); | ||
626 | MoveAngular(pTimestep); | ||
627 | LimitRotation(pTimestep); | ||
628 | }// end Step | ||
629 | |||
630 | private void MoveLinear(float pTimestep, OdeScene _pParentScene) | ||
631 | { | ||
632 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant | ||
633 | { | ||
634 | if (!d.BodyIsEnabled(Body)) | ||
635 | d.BodyEnable(Body); | ||
636 | |||
637 | // add drive to body | ||
638 | Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); | ||
639 | m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? | ||
640 | |||
641 | // This will work temporarily, but we really need to compare speed on an axis | ||
642 | // KF: Limit body velocity to applied velocity? | ||
643 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | ||
644 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | ||
645 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | ||
646 | m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; | ||
647 | if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) | ||
648 | m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; | ||
649 | |||
650 | // decay applied velocity | ||
651 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | ||
652 | //Console.WriteLine("decay: " + decayfraction); | ||
653 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; | ||
654 | //Console.WriteLine("actual: " + m_linearMotorDirection); | ||
655 | } | ||
656 | else | ||
657 | { // requested is not significant | ||
658 | // if what remains of applied is small, zero it. | ||
659 | if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) | ||
660 | m_lastLinearVelocityVector = Vector3.Zero; | ||
661 | } | ||
662 | |||
663 | // convert requested object velocity to world-referenced vector | ||
664 | m_dir = m_lastLinearVelocityVector; | ||
665 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
666 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object | ||
667 | m_dir *= rotq; // apply obj rotation to velocity vector | ||
668 | |||
669 | // add Gravity andBuoyancy | ||
670 | // KF: So far I have found no good method to combine a script-requested | ||
671 | // .Z velocity and gravity. Therefore only 0g will used script-requested | ||
672 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. | ||
673 | Vector3 grav = Vector3.Zero; | ||
674 | // There is some gravity, make a gravity force vector | ||
675 | // that is applied after object velocity. | ||
676 | d.Mass objMass; | ||
677 | d.BodyGetMass(Body, out objMass); | ||
678 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
679 | grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); | ||
680 | // Preserve the current Z velocity | ||
681 | d.Vector3 vel_now = d.BodyGetLinearVel(Body); | ||
682 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | ||
683 | |||
684 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
685 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); | ||
686 | Vector3 posChange = new Vector3(); | ||
687 | posChange.X = pos.X - m_lastPositionVector.X; | ||
688 | posChange.Y = pos.Y - m_lastPositionVector.Y; | ||
689 | posChange.Z = pos.Z - m_lastPositionVector.Z; | ||
690 | double Zchange = Math.Abs(posChange.Z); | ||
691 | if (m_BlockingEndPoint != Vector3.Zero) | ||
692 | { | ||
693 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | ||
694 | { | ||
695 | pos.X -= posChange.X + 1; | ||
696 | d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); | ||
697 | } | ||
698 | if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) | ||
699 | { | ||
700 | pos.Y -= posChange.Y + 1; | ||
701 | d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); | ||
702 | } | ||
703 | if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) | ||
704 | { | ||
705 | pos.Z -= posChange.Z + 1; | ||
706 | d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); | ||
707 | } | ||
708 | if (pos.X <= 0) | ||
709 | { | ||
710 | pos.X += posChange.X + 1; | ||
711 | d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); | ||
712 | } | ||
713 | if (pos.Y <= 0) | ||
714 | { | ||
715 | pos.Y += posChange.Y + 1; | ||
716 | d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); | ||
717 | } | ||
718 | } | ||
719 | if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) | ||
720 | { | ||
721 | pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; | ||
722 | d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); | ||
723 | } | ||
724 | |||
725 | // Check if hovering | ||
726 | if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | ||
727 | { | ||
728 | // We should hover, get the target height | ||
729 | if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) | ||
730 | { | ||
731 | m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; | ||
732 | } | ||
733 | if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | ||
734 | { | ||
735 | m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; | ||
736 | } | ||
737 | if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | ||
738 | { | ||
739 | m_VhoverTargetHeight = m_VhoverHeight; | ||
740 | } | ||
741 | |||
742 | if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) | ||
743 | { | ||
744 | // If body is aready heigher, use its height as target height | ||
745 | if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; | ||
746 | } | ||
747 | if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | ||
748 | { | ||
749 | if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) | ||
750 | { | ||
751 | d.BodySetPosition(Body, pos.X, pos.Y, m_VhoverTargetHeight); | ||
752 | } | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | float herr0 = pos.Z - m_VhoverTargetHeight; | ||
757 | // Replace Vertical speed with correction figure if significant | ||
758 | if (Math.Abs(herr0) > 0.01f) | ||
759 | { | ||
760 | m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); | ||
761 | //KF: m_VhoverEfficiency is not yet implemented | ||
762 | } | ||
763 | else | ||
764 | { | ||
765 | m_dir.Z = 0f; | ||
766 | } | ||
767 | } | ||
768 | |||
769 | // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped | ||
770 | // m_VhoverTimescale = 0f; // time to acheive height | ||
771 | // pTimestep is time since last frame,in secs | ||
772 | } | ||
773 | |||
774 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | ||
775 | { | ||
776 | //Start Experimental Values | ||
777 | if (Zchange > .3) | ||
778 | { | ||
779 | grav.Z = (float)(grav.Z * 3); | ||
780 | } | ||
781 | if (Zchange > .15) | ||
782 | { | ||
783 | grav.Z = (float)(grav.Z * 2); | ||
784 | } | ||
785 | if (Zchange > .75) | ||
786 | { | ||
787 | grav.Z = (float)(grav.Z * 1.5); | ||
788 | } | ||
789 | if (Zchange > .05) | ||
790 | { | ||
791 | grav.Z = (float)(grav.Z * 1.25); | ||
792 | } | ||
793 | if (Zchange > .025) | ||
794 | { | ||
795 | grav.Z = (float)(grav.Z * 1.125); | ||
796 | } | ||
797 | float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); | ||
798 | float postemp = (pos.Z - terraintemp); | ||
799 | if (postemp > 2.5f) | ||
800 | { | ||
801 | grav.Z = (float)(grav.Z * 1.037125); | ||
802 | } | ||
803 | //End Experimental Values | ||
804 | } | ||
805 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
806 | { | ||
807 | m_dir.X = 0; | ||
808 | } | ||
809 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
810 | { | ||
811 | m_dir.Y = 0; | ||
812 | } | ||
813 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
814 | { | ||
815 | m_dir.Z = 0; | ||
816 | } | ||
817 | |||
818 | m_lastPositionVector = d.BodyGetPosition(Body); | ||
819 | |||
820 | // Apply velocity | ||
821 | d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); | ||
822 | // apply gravity force | ||
823 | d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); | ||
824 | |||
825 | |||
826 | // apply friction | ||
827 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); | ||
828 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; | ||
829 | } // end MoveLinear() | ||
830 | |||
831 | private void MoveAngular(float pTimestep) | ||
832 | { | ||
833 | /* | ||
834 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | ||
835 | private int m_angularMotorApply = 0; // application frame counter | ||
836 | private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) | ||
837 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | ||
838 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | ||
839 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | ||
840 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | ||
841 | */ | ||
842 | |||
843 | // Get what the body is doing, this includes 'external' influences | ||
844 | d.Vector3 angularVelocity = d.BodyGetAngularVel(Body); | ||
845 | // Vector3 angularVelocity = Vector3.Zero; | ||
846 | |||
847 | if (m_angularMotorApply > 0) | ||
848 | { | ||
849 | // ramp up to new value | ||
850 | // current velocity += error / (time to get there / step interval) | ||
851 | // requested speed - last motor speed | ||
852 | m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); | ||
853 | m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); | ||
854 | m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); | ||
855 | |||
856 | m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected | ||
857 | // velocity may still be acheived. | ||
858 | } | ||
859 | else | ||
860 | { | ||
861 | // no motor recently applied, keep the body velocity | ||
862 | /* m_angularMotorVelocity.X = angularVelocity.X; | ||
863 | m_angularMotorVelocity.Y = angularVelocity.Y; | ||
864 | m_angularMotorVelocity.Z = angularVelocity.Z; */ | ||
865 | |||
866 | // and decay the velocity | ||
867 | m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); | ||
868 | } // end motor section | ||
869 | |||
870 | // Vertical attractor section | ||
871 | Vector3 vertattr = Vector3.Zero; | ||
872 | |||
873 | if (m_verticalAttractionTimescale < 300) | ||
874 | { | ||
875 | float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); | ||
876 | // get present body rotation | ||
877 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
878 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); | ||
879 | // make a vector pointing up | ||
880 | Vector3 verterr = Vector3.Zero; | ||
881 | verterr.Z = 1.0f; | ||
882 | // rotate it to Body Angle | ||
883 | verterr = verterr * rotq; | ||
884 | // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. | ||
885 | // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go | ||
886 | // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. | ||
887 | if (verterr.Z < 0.0f) | ||
888 | { | ||
889 | verterr.X = 2.0f - verterr.X; | ||
890 | verterr.Y = 2.0f - verterr.Y; | ||
891 | } | ||
892 | // Error is 0 (no error) to +/- 2 (max error) | ||
893 | // scale it by VAservo | ||
894 | verterr = verterr * VAservo; | ||
895 | //if (frcount == 0) Console.WriteLine("VAerr=" + verterr); | ||
896 | |||
897 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so | ||
898 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. | ||
899 | vertattr.X = verterr.Y; | ||
900 | vertattr.Y = - verterr.X; | ||
901 | vertattr.Z = 0f; | ||
902 | |||
903 | // scaling appears better usingsquare-law | ||
904 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
905 | vertattr.X += bounce * angularVelocity.X; | ||
906 | vertattr.Y += bounce * angularVelocity.Y; | ||
907 | |||
908 | } // else vertical attractor is off | ||
909 | |||
910 | // m_lastVertAttractor = vertattr; | ||
911 | |||
912 | // Bank section tba | ||
913 | // Deflection section tba | ||
914 | |||
915 | // Sum velocities | ||
916 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection | ||
917 | |||
918 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
919 | { | ||
920 | m_lastAngularVelocity.X = 0; | ||
921 | m_lastAngularVelocity.Y = 0; | ||
922 | } | ||
923 | |||
924 | if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
925 | { | ||
926 | if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | ||
927 | } | ||
928 | else | ||
929 | { | ||
930 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | ||
931 | } | ||
932 | |||
933 | // apply friction | ||
934 | Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); | ||
935 | m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; | ||
936 | |||
937 | // Apply to the body | ||
938 | d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z); | ||
939 | |||
940 | } //end MoveAngular | ||
941 | internal void LimitRotation(float timestep) | ||
942 | { | ||
943 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
944 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object | ||
945 | d.Quaternion m_rot = new d.Quaternion(); | ||
946 | bool changed = false; | ||
947 | m_rot.X = rotq.X; | ||
948 | m_rot.Y = rotq.Y; | ||
949 | m_rot.Z = rotq.Z; | ||
950 | m_rot.W = rotq.W; | ||
951 | if (m_RollreferenceFrame != Quaternion.Identity) | ||
952 | { | ||
953 | if (rotq.X >= m_RollreferenceFrame.X) | ||
954 | { | ||
955 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); | ||
956 | } | ||
957 | if (rotq.Y >= m_RollreferenceFrame.Y) | ||
958 | { | ||
959 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); | ||
960 | } | ||
961 | if (rotq.X <= -m_RollreferenceFrame.X) | ||
962 | { | ||
963 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); | ||
964 | } | ||
965 | if (rotq.Y <= -m_RollreferenceFrame.Y) | ||
966 | { | ||
967 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); | ||
968 | } | ||
969 | changed = true; | ||
970 | } | ||
971 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) | ||
972 | { | ||
973 | m_rot.X = 0; | ||
974 | m_rot.Y = 0; | ||
975 | changed = true; | ||
976 | } | ||
977 | if (changed) | ||
978 | d.BodySetQuaternion(Body, ref m_rot); | ||
979 | } | ||
980 | } | ||
981 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEModule.cs b/OpenSim/Region/PhysicsModules/Ode/ODEModule.cs new file mode 100644 index 0000000..22fc84d --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODEModule.cs | |||
@@ -0,0 +1,89 @@ | |||
1 | using System; | ||
2 | using System.Reflection; | ||
3 | using log4net; | ||
4 | using Nini.Config; | ||
5 | using Mono.Addins; | ||
6 | using OpenSim.Framework; | ||
7 | using OpenSim.Region.Framework.Scenes; | ||
8 | using OpenSim.Region.Framework.Interfaces; | ||
9 | |||
10 | namespace OpenSim.Region.PhysicsModule.ODE | ||
11 | { | ||
12 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ODEPhysicsScene")] | ||
13 | public class OdeModule : INonSharedRegionModule | ||
14 | { | ||
15 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
16 | |||
17 | private bool m_Enabled = false; | ||
18 | private IConfigSource m_config; | ||
19 | private OdeScene m_scene; | ||
20 | |||
21 | #region INonSharedRegionModule | ||
22 | |||
23 | public string Name | ||
24 | { | ||
25 | get { return "OpenDynamicsEngine"; } | ||
26 | } | ||
27 | |||
28 | public string Version | ||
29 | { | ||
30 | get { return "1.0"; } | ||
31 | } | ||
32 | |||
33 | public Type ReplaceableInterface | ||
34 | { | ||
35 | get { return null; } | ||
36 | } | ||
37 | |||
38 | public void Initialise(IConfigSource source) | ||
39 | { | ||
40 | IConfig config = source.Configs["Startup"]; | ||
41 | if (config != null) | ||
42 | { | ||
43 | string physics = config.GetString("physics", string.Empty); | ||
44 | if (physics == Name) | ||
45 | { | ||
46 | m_config = source; | ||
47 | m_Enabled = true; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | |||
52 | public void Close() | ||
53 | { | ||
54 | } | ||
55 | |||
56 | public void AddRegion(Scene scene) | ||
57 | { | ||
58 | if (!m_Enabled) | ||
59 | return; | ||
60 | |||
61 | if (Util.IsWindows()) | ||
62 | Util.LoadArchSpecificWindowsDll("ode.dll"); | ||
63 | |||
64 | // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to | ||
65 | // http://opensimulator.org/mantis/view.php?id=2750). | ||
66 | d.InitODE(); | ||
67 | |||
68 | m_scene = new OdeScene(scene, m_config, Name, Version); | ||
69 | } | ||
70 | |||
71 | public void RemoveRegion(Scene scene) | ||
72 | { | ||
73 | if (!m_Enabled || m_scene == null) | ||
74 | return; | ||
75 | |||
76 | m_scene.Dispose(); | ||
77 | m_scene = null; | ||
78 | } | ||
79 | |||
80 | public void RegionLoaded(Scene scene) | ||
81 | { | ||
82 | if (!m_Enabled || m_scene == null) | ||
83 | return; | ||
84 | |||
85 | m_scene.RegionLoaded(); | ||
86 | } | ||
87 | #endregion | ||
88 | } | ||
89 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs b/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs new file mode 100644 index 0000000..8934330 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs | |||
@@ -0,0 +1,3206 @@ | |||
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 | /* | ||
29 | * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
30 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
31 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
32 | * characteristics and Kinetic motion. | ||
33 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
34 | * (dynamics) and the associated settings. Old Linear and angular | ||
35 | * motors for dynamic motion have been replace with MoveLinear() | ||
36 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
37 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
38 | * switch between 'VEHICLE' parameter use and general dynamics | ||
39 | * settings use. | ||
40 | */ | ||
41 | |||
42 | //#define SPAM | ||
43 | |||
44 | using System; | ||
45 | using System.Collections.Generic; | ||
46 | using System.Reflection; | ||
47 | using System.Runtime.InteropServices; | ||
48 | using System.Threading; | ||
49 | using log4net; | ||
50 | using OpenMetaverse; | ||
51 | using OpenSim.Framework; | ||
52 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
53 | |||
54 | namespace OpenSim.Region.PhysicsModule.ODE | ||
55 | { | ||
56 | /// <summary> | ||
57 | /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. | ||
58 | /// </summary> | ||
59 | public class OdePrim : PhysicsActor | ||
60 | { | ||
61 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
62 | |||
63 | private bool m_isphysical; | ||
64 | |||
65 | public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } } | ||
66 | private int m_expectedCollisionContacts = 0; | ||
67 | |||
68 | /// <summary> | ||
69 | /// Gets collide bits so that we can still perform land collisions if a mesh fails to load. | ||
70 | /// </summary> | ||
71 | private int BadMeshAssetCollideBits | ||
72 | { | ||
73 | get { return m_isphysical ? (int)CollisionCategories.Land : 0; } | ||
74 | } | ||
75 | |||
76 | /// <summary> | ||
77 | /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. | ||
78 | /// </summary> | ||
79 | public override bool IsPhysical | ||
80 | { | ||
81 | get { return m_isphysical; } | ||
82 | set | ||
83 | { | ||
84 | m_isphysical = value; | ||
85 | if (!m_isphysical) | ||
86 | { | ||
87 | _zeroFlag = true; // Zero the remembered last velocity | ||
88 | m_lastVelocity = Vector3.Zero; | ||
89 | _acceleration = Vector3.Zero; | ||
90 | _velocity = Vector3.Zero; | ||
91 | m_taintVelocity = Vector3.Zero; | ||
92 | m_rotationalVelocity = Vector3.Zero; | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | private Vector3 _position; | ||
98 | private Vector3 _velocity; | ||
99 | private Vector3 _torque; | ||
100 | private Vector3 m_lastVelocity; | ||
101 | private Vector3 m_lastposition; | ||
102 | private Quaternion m_lastorientation = new Quaternion(); | ||
103 | private Vector3 m_rotationalVelocity; | ||
104 | private Vector3 _size; | ||
105 | private Vector3 _acceleration; | ||
106 | // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f); | ||
107 | private Quaternion _orientation; | ||
108 | private Vector3 m_taintposition; | ||
109 | private Vector3 m_taintsize; | ||
110 | private Vector3 m_taintVelocity; | ||
111 | private Vector3 m_taintTorque; | ||
112 | private Quaternion m_taintrot; | ||
113 | |||
114 | private IntPtr Amotor = IntPtr.Zero; | ||
115 | |||
116 | private byte m_taintAngularLock = 0; | ||
117 | private byte m_angularlock = 0; | ||
118 | |||
119 | private bool m_assetFailed = false; | ||
120 | |||
121 | private Vector3 m_PIDTarget; | ||
122 | private float m_PIDTau; | ||
123 | private float PID_D = 35f; | ||
124 | private float PID_G = 25f; | ||
125 | |||
126 | // KF: These next 7 params apply to llSetHoverHeight(float height, integer water, float tau), | ||
127 | // and are for non-VEHICLES only. | ||
128 | |||
129 | private float m_PIDHoverHeight; | ||
130 | private float m_PIDHoverTau; | ||
131 | private bool m_useHoverPID; | ||
132 | private PIDHoverType m_PIDHoverType = PIDHoverType.Ground; | ||
133 | private float m_targetHoverHeight; | ||
134 | private float m_groundHeight; | ||
135 | private float m_waterHeight; | ||
136 | private float m_buoyancy; //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle. | ||
137 | |||
138 | // private float m_tensor = 5f; | ||
139 | private int body_autodisable_frames = 20; | ||
140 | |||
141 | |||
142 | private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom | ||
143 | | CollisionCategories.Space | ||
144 | | CollisionCategories.Body | ||
145 | | CollisionCategories.Character | ||
146 | ); | ||
147 | private bool m_taintshape; | ||
148 | private bool m_taintPhysics; | ||
149 | private bool m_collidesLand = true; | ||
150 | private bool m_collidesWater; | ||
151 | |||
152 | // Default we're a Geometry | ||
153 | private CollisionCategories m_collisionCategories = (CollisionCategories.Geom); | ||
154 | |||
155 | // Default, Collide with Other Geometries, spaces and Bodies | ||
156 | private CollisionCategories m_collisionFlags = m_default_collisionFlags; | ||
157 | |||
158 | public bool m_taintremove { get; private set; } | ||
159 | public bool m_taintdisable { get; private set; } | ||
160 | internal bool m_disabled; | ||
161 | public bool m_taintadd { get; private set; } | ||
162 | public bool m_taintselected { get; private set; } | ||
163 | public bool m_taintCollidesWater { get; private set; } | ||
164 | |||
165 | private bool m_taintforce = false; | ||
166 | private bool m_taintaddangularforce = false; | ||
167 | private Vector3 m_force; | ||
168 | private List<Vector3> m_forcelist = new List<Vector3>(); | ||
169 | private List<Vector3> m_angularforcelist = new List<Vector3>(); | ||
170 | |||
171 | private PrimitiveBaseShape _pbs; | ||
172 | private OdeScene _parent_scene; | ||
173 | |||
174 | /// <summary> | ||
175 | /// The physics space which contains prim geometries | ||
176 | /// </summary> | ||
177 | public IntPtr m_targetSpace = IntPtr.Zero; | ||
178 | |||
179 | /// <summary> | ||
180 | /// The prim geometry, used for collision detection. | ||
181 | /// </summary> | ||
182 | /// <remarks> | ||
183 | /// This is never null except for a brief period when the geometry needs to be replaced (due to resizing or | ||
184 | /// mesh change) or when the physical prim is being removed from the scene. | ||
185 | /// </remarks> | ||
186 | public IntPtr prim_geom { get; private set; } | ||
187 | |||
188 | public IntPtr _triMeshData { get; private set; } | ||
189 | |||
190 | private IntPtr _linkJointGroup = IntPtr.Zero; | ||
191 | private PhysicsActor _parent; | ||
192 | private PhysicsActor m_taintparent; | ||
193 | |||
194 | private List<OdePrim> childrenPrim = new List<OdePrim>(); | ||
195 | |||
196 | private bool iscolliding; | ||
197 | private bool m_isSelected; | ||
198 | |||
199 | internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively | ||
200 | |||
201 | private bool m_throttleUpdates; | ||
202 | private int throttleCounter; | ||
203 | public int m_interpenetrationcount { get; private set; } | ||
204 | internal float m_collisionscore; | ||
205 | public int m_roundsUnderMotionThreshold { get; private set; } | ||
206 | |||
207 | public bool outofBounds { get; private set; } | ||
208 | private float m_density = 10.000006836f; // Aluminum g/cm3; | ||
209 | |||
210 | public bool _zeroFlag { get; private set; } | ||
211 | private bool m_lastUpdateSent; | ||
212 | |||
213 | public IntPtr Body = IntPtr.Zero; | ||
214 | private Vector3 _target_velocity; | ||
215 | private d.Mass pMass; | ||
216 | |||
217 | private int m_eventsubscription; | ||
218 | private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
219 | |||
220 | /// <summary> | ||
221 | /// Signal whether there were collisions on the previous frame, so we know if we need to send the | ||
222 | /// empty CollisionEventsThisFrame to the prim so that it can detect the end of a collision. | ||
223 | /// </summary> | ||
224 | /// <remarks> | ||
225 | /// This is probably a temporary measure, pending storing this information consistently in CollisionEventUpdate itself. | ||
226 | /// </remarks> | ||
227 | private bool m_collisionsOnPreviousFrame; | ||
228 | |||
229 | private IntPtr m_linkJoint = IntPtr.Zero; | ||
230 | |||
231 | internal volatile bool childPrim; | ||
232 | |||
233 | private ODEDynamics m_vehicle; | ||
234 | |||
235 | internal int m_material = (int)Material.Wood; | ||
236 | |||
237 | public OdePrim( | ||
238 | String primName, OdeScene parent_scene, Vector3 pos, Vector3 size, | ||
239 | Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
240 | { | ||
241 | Name = primName; | ||
242 | m_vehicle = new ODEDynamics(); | ||
243 | //gc = GCHandle.Alloc(prim_geom, GCHandleType.Pinned); | ||
244 | |||
245 | if (!pos.IsFinite()) | ||
246 | { | ||
247 | pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), | ||
248 | parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f); | ||
249 | m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Position for {0}", Name); | ||
250 | } | ||
251 | _position = pos; | ||
252 | m_taintposition = pos; | ||
253 | PID_D = parent_scene.bodyPIDD; | ||
254 | PID_G = parent_scene.bodyPIDG; | ||
255 | m_density = parent_scene.geomDefaultDensity; | ||
256 | // m_tensor = parent_scene.bodyMotorJointMaxforceTensor; | ||
257 | body_autodisable_frames = parent_scene.bodyFramesAutoDisable; | ||
258 | |||
259 | prim_geom = IntPtr.Zero; | ||
260 | |||
261 | if (!pos.IsFinite()) | ||
262 | { | ||
263 | size = new Vector3(0.5f, 0.5f, 0.5f); | ||
264 | m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Size for {0}", Name); | ||
265 | } | ||
266 | |||
267 | if (size.X <= 0) size.X = 0.01f; | ||
268 | if (size.Y <= 0) size.Y = 0.01f; | ||
269 | if (size.Z <= 0) size.Z = 0.01f; | ||
270 | |||
271 | _size = size; | ||
272 | m_taintsize = _size; | ||
273 | |||
274 | if (!QuaternionIsFinite(rotation)) | ||
275 | { | ||
276 | rotation = Quaternion.Identity; | ||
277 | m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Rotation for {0}", Name); | ||
278 | } | ||
279 | |||
280 | _orientation = rotation; | ||
281 | m_taintrot = _orientation; | ||
282 | _pbs = pbs; | ||
283 | |||
284 | _parent_scene = parent_scene; | ||
285 | m_targetSpace = (IntPtr)0; | ||
286 | |||
287 | if (pos.Z < 0) | ||
288 | { | ||
289 | IsPhysical = false; | ||
290 | } | ||
291 | else | ||
292 | { | ||
293 | IsPhysical = pisPhysical; | ||
294 | // If we're physical, we need to be in the master space for now. | ||
295 | // linksets *should* be in a space together.. but are not currently | ||
296 | if (IsPhysical) | ||
297 | m_targetSpace = _parent_scene.space; | ||
298 | } | ||
299 | |||
300 | m_taintadd = true; | ||
301 | m_assetFailed = false; | ||
302 | _parent_scene.AddPhysicsActorTaint(this); | ||
303 | } | ||
304 | |||
305 | public override int PhysicsActorType | ||
306 | { | ||
307 | get { return (int) ActorTypes.Prim; } | ||
308 | set { return; } | ||
309 | } | ||
310 | |||
311 | public override bool SetAlwaysRun | ||
312 | { | ||
313 | get { return false; } | ||
314 | set { return; } | ||
315 | } | ||
316 | |||
317 | public override bool Grabbed | ||
318 | { | ||
319 | set { return; } | ||
320 | } | ||
321 | |||
322 | public override bool Selected | ||
323 | { | ||
324 | set | ||
325 | { | ||
326 | // This only makes the object not collidable if the object | ||
327 | // is physical or the object is modified somehow *IN THE FUTURE* | ||
328 | // without this, if an avatar selects prim, they can walk right | ||
329 | // through it while it's selected | ||
330 | m_collisionscore = 0; | ||
331 | |||
332 | if ((IsPhysical && !_zeroFlag) || !value) | ||
333 | { | ||
334 | m_taintselected = value; | ||
335 | _parent_scene.AddPhysicsActorTaint(this); | ||
336 | } | ||
337 | else | ||
338 | { | ||
339 | m_taintselected = value; | ||
340 | m_isSelected = value; | ||
341 | } | ||
342 | |||
343 | if (m_isSelected) | ||
344 | disableBodySoft(); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /// <summary> | ||
349 | /// Set a new geometry for this prim. | ||
350 | /// </summary> | ||
351 | /// <param name="geom"></param> | ||
352 | private void SetGeom(IntPtr geom) | ||
353 | { | ||
354 | prim_geom = geom; | ||
355 | //Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); | ||
356 | |||
357 | if (m_assetFailed) | ||
358 | { | ||
359 | d.GeomSetCategoryBits(prim_geom, 0); | ||
360 | d.GeomSetCollideBits(prim_geom, (uint)BadMeshAssetCollideBits); | ||
361 | } | ||
362 | else | ||
363 | { | ||
364 | d.GeomSetCategoryBits(prim_geom, (uint)m_collisionCategories); | ||
365 | d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); | ||
366 | } | ||
367 | |||
368 | _parent_scene.geom_name_map[prim_geom] = Name; | ||
369 | _parent_scene.actor_name_map[prim_geom] = this; | ||
370 | |||
371 | if (childPrim) | ||
372 | { | ||
373 | if (_parent != null && _parent is OdePrim) | ||
374 | { | ||
375 | OdePrim parent = (OdePrim)_parent; | ||
376 | //Console.WriteLine("SetGeom calls ChildSetGeom"); | ||
377 | parent.ChildSetGeom(this); | ||
378 | } | ||
379 | } | ||
380 | //m_log.Warn("Setting Geom to: " + prim_geom); | ||
381 | } | ||
382 | |||
383 | private void enableBodySoft() | ||
384 | { | ||
385 | if (!childPrim) | ||
386 | { | ||
387 | if (IsPhysical && Body != IntPtr.Zero) | ||
388 | { | ||
389 | d.BodyEnable(Body); | ||
390 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
391 | m_vehicle.Enable(Body, _parent_scene); | ||
392 | } | ||
393 | |||
394 | m_disabled = false; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | private void disableBodySoft() | ||
399 | { | ||
400 | m_disabled = true; | ||
401 | |||
402 | if (IsPhysical && Body != IntPtr.Zero) | ||
403 | { | ||
404 | d.BodyDisable(Body); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | /// <summary> | ||
409 | /// Make a prim subject to physics. | ||
410 | /// </summary> | ||
411 | private void enableBody() | ||
412 | { | ||
413 | // Don't enable this body if we're a child prim | ||
414 | // this should be taken care of in the parent function not here | ||
415 | if (!childPrim) | ||
416 | { | ||
417 | // Sets the geom to a body | ||
418 | Body = d.BodyCreate(_parent_scene.world); | ||
419 | |||
420 | setMass(); | ||
421 | d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); | ||
422 | d.Quaternion myrot = new d.Quaternion(); | ||
423 | myrot.X = _orientation.X; | ||
424 | myrot.Y = _orientation.Y; | ||
425 | myrot.Z = _orientation.Z; | ||
426 | myrot.W = _orientation.W; | ||
427 | d.BodySetQuaternion(Body, ref myrot); | ||
428 | d.GeomSetBody(prim_geom, Body); | ||
429 | |||
430 | if (m_assetFailed) | ||
431 | { | ||
432 | d.GeomSetCategoryBits(prim_geom, 0); | ||
433 | d.GeomSetCollideBits(prim_geom, (uint)BadMeshAssetCollideBits); | ||
434 | } | ||
435 | else | ||
436 | { | ||
437 | m_collisionCategories |= CollisionCategories.Body; | ||
438 | m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); | ||
439 | } | ||
440 | |||
441 | d.GeomSetCategoryBits(prim_geom, (uint)m_collisionCategories); | ||
442 | d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); | ||
443 | |||
444 | d.BodySetAutoDisableFlag(Body, true); | ||
445 | d.BodySetAutoDisableSteps(Body, body_autodisable_frames); | ||
446 | |||
447 | // disconnect from world gravity so we can apply buoyancy | ||
448 | d.BodySetGravityMode (Body, false); | ||
449 | |||
450 | m_interpenetrationcount = 0; | ||
451 | m_collisionscore = 0; | ||
452 | m_disabled = false; | ||
453 | |||
454 | // The body doesn't already have a finite rotation mode set here | ||
455 | if (m_angularlock != 0 && _parent == null) | ||
456 | { | ||
457 | createAMotor(m_angularlock); | ||
458 | } | ||
459 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
460 | { | ||
461 | m_vehicle.Enable(Body, _parent_scene); | ||
462 | } | ||
463 | |||
464 | _parent_scene.ActivatePrim(this); | ||
465 | } | ||
466 | } | ||
467 | |||
468 | #region Mass Calculation | ||
469 | |||
470 | private float CalculateMass() | ||
471 | { | ||
472 | float volume = _size.X * _size.Y * _size.Z; // default | ||
473 | float tmp; | ||
474 | |||
475 | float returnMass = 0; | ||
476 | float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; | ||
477 | float hollowVolume = hollowAmount * hollowAmount; | ||
478 | |||
479 | switch (_pbs.ProfileShape) | ||
480 | { | ||
481 | case ProfileShape.Square: | ||
482 | // default box | ||
483 | |||
484 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
485 | { | ||
486 | if (hollowAmount > 0.0) | ||
487 | { | ||
488 | switch (_pbs.HollowShape) | ||
489 | { | ||
490 | case HollowShape.Square: | ||
491 | case HollowShape.Same: | ||
492 | break; | ||
493 | |||
494 | case HollowShape.Circle: | ||
495 | |||
496 | hollowVolume *= 0.78539816339f; | ||
497 | break; | ||
498 | |||
499 | case HollowShape.Triangle: | ||
500 | |||
501 | hollowVolume *= (0.5f * .5f); | ||
502 | break; | ||
503 | |||
504 | default: | ||
505 | hollowVolume = 0; | ||
506 | break; | ||
507 | } | ||
508 | volume *= (1.0f - hollowVolume); | ||
509 | } | ||
510 | } | ||
511 | |||
512 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
513 | { | ||
514 | //a tube | ||
515 | |||
516 | volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); | ||
517 | tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); | ||
518 | volume -= volume*tmp*tmp; | ||
519 | |||
520 | if (hollowAmount > 0.0) | ||
521 | { | ||
522 | hollowVolume *= hollowAmount; | ||
523 | |||
524 | switch (_pbs.HollowShape) | ||
525 | { | ||
526 | case HollowShape.Square: | ||
527 | case HollowShape.Same: | ||
528 | break; | ||
529 | |||
530 | case HollowShape.Circle: | ||
531 | hollowVolume *= 0.78539816339f;; | ||
532 | break; | ||
533 | |||
534 | case HollowShape.Triangle: | ||
535 | hollowVolume *= 0.5f * 0.5f; | ||
536 | break; | ||
537 | default: | ||
538 | hollowVolume = 0; | ||
539 | break; | ||
540 | } | ||
541 | volume *= (1.0f - hollowVolume); | ||
542 | } | ||
543 | } | ||
544 | |||
545 | break; | ||
546 | |||
547 | case ProfileShape.Circle: | ||
548 | |||
549 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
550 | { | ||
551 | volume *= 0.78539816339f; // elipse base | ||
552 | |||
553 | if (hollowAmount > 0.0) | ||
554 | { | ||
555 | switch (_pbs.HollowShape) | ||
556 | { | ||
557 | case HollowShape.Same: | ||
558 | case HollowShape.Circle: | ||
559 | break; | ||
560 | |||
561 | case HollowShape.Square: | ||
562 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
563 | break; | ||
564 | |||
565 | case HollowShape.Triangle: | ||
566 | hollowVolume *= .5f * 1.27323954473516f; | ||
567 | break; | ||
568 | |||
569 | default: | ||
570 | hollowVolume = 0; | ||
571 | break; | ||
572 | } | ||
573 | volume *= (1.0f - hollowVolume); | ||
574 | } | ||
575 | } | ||
576 | |||
577 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
578 | { | ||
579 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); | ||
580 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | ||
581 | volume *= (1.0f - tmp * tmp); | ||
582 | |||
583 | if (hollowAmount > 0.0) | ||
584 | { | ||
585 | |||
586 | // calculate the hollow volume by it's shape compared to the prim shape | ||
587 | hollowVolume *= hollowAmount; | ||
588 | |||
589 | switch (_pbs.HollowShape) | ||
590 | { | ||
591 | case HollowShape.Same: | ||
592 | case HollowShape.Circle: | ||
593 | break; | ||
594 | |||
595 | case HollowShape.Square: | ||
596 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
597 | break; | ||
598 | |||
599 | case HollowShape.Triangle: | ||
600 | hollowVolume *= .5f * 1.27323954473516f; | ||
601 | break; | ||
602 | |||
603 | default: | ||
604 | hollowVolume = 0; | ||
605 | break; | ||
606 | } | ||
607 | volume *= (1.0f - hollowVolume); | ||
608 | } | ||
609 | } | ||
610 | break; | ||
611 | |||
612 | case ProfileShape.HalfCircle: | ||
613 | if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
614 | { | ||
615 | volume *= 0.52359877559829887307710723054658f; | ||
616 | } | ||
617 | break; | ||
618 | |||
619 | case ProfileShape.EquilateralTriangle: | ||
620 | |||
621 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
622 | { | ||
623 | volume *= 0.32475953f; | ||
624 | |||
625 | if (hollowAmount > 0.0) | ||
626 | { | ||
627 | |||
628 | // calculate the hollow volume by it's shape compared to the prim shape | ||
629 | switch (_pbs.HollowShape) | ||
630 | { | ||
631 | case HollowShape.Same: | ||
632 | case HollowShape.Triangle: | ||
633 | hollowVolume *= .25f; | ||
634 | break; | ||
635 | |||
636 | case HollowShape.Square: | ||
637 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
638 | break; | ||
639 | |||
640 | case HollowShape.Circle: | ||
641 | // Hollow shape is a perfect cyllinder in respect to the cube's scale | ||
642 | // Cyllinder hollow volume calculation | ||
643 | |||
644 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
645 | break; | ||
646 | |||
647 | default: | ||
648 | hollowVolume = 0; | ||
649 | break; | ||
650 | } | ||
651 | volume *= (1.0f - hollowVolume); | ||
652 | } | ||
653 | } | ||
654 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
655 | { | ||
656 | volume *= 0.32475953f; | ||
657 | volume *= 0.01f * (float)(200 - _pbs.PathScaleX); | ||
658 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | ||
659 | volume *= (1.0f - tmp * tmp); | ||
660 | |||
661 | if (hollowAmount > 0.0) | ||
662 | { | ||
663 | |||
664 | hollowVolume *= hollowAmount; | ||
665 | |||
666 | switch (_pbs.HollowShape) | ||
667 | { | ||
668 | case HollowShape.Same: | ||
669 | case HollowShape.Triangle: | ||
670 | hollowVolume *= .25f; | ||
671 | break; | ||
672 | |||
673 | case HollowShape.Square: | ||
674 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
675 | break; | ||
676 | |||
677 | case HollowShape.Circle: | ||
678 | |||
679 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
680 | break; | ||
681 | |||
682 | default: | ||
683 | hollowVolume = 0; | ||
684 | break; | ||
685 | } | ||
686 | volume *= (1.0f - hollowVolume); | ||
687 | } | ||
688 | } | ||
689 | break; | ||
690 | |||
691 | default: | ||
692 | break; | ||
693 | } | ||
694 | |||
695 | float taperX1; | ||
696 | float taperY1; | ||
697 | float taperX; | ||
698 | float taperY; | ||
699 | float pathBegin; | ||
700 | float pathEnd; | ||
701 | float profileBegin; | ||
702 | float profileEnd; | ||
703 | |||
704 | if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) | ||
705 | { | ||
706 | taperX1 = _pbs.PathScaleX * 0.01f; | ||
707 | if (taperX1 > 1.0f) | ||
708 | taperX1 = 2.0f - taperX1; | ||
709 | taperX = 1.0f - taperX1; | ||
710 | |||
711 | taperY1 = _pbs.PathScaleY * 0.01f; | ||
712 | if (taperY1 > 1.0f) | ||
713 | taperY1 = 2.0f - taperY1; | ||
714 | taperY = 1.0f - taperY1; | ||
715 | } | ||
716 | else | ||
717 | { | ||
718 | taperX = _pbs.PathTaperX * 0.01f; | ||
719 | if (taperX < 0.0f) | ||
720 | taperX = -taperX; | ||
721 | taperX1 = 1.0f - taperX; | ||
722 | |||
723 | taperY = _pbs.PathTaperY * 0.01f; | ||
724 | if (taperY < 0.0f) | ||
725 | taperY = -taperY; | ||
726 | taperY1 = 1.0f - taperY; | ||
727 | } | ||
728 | |||
729 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | ||
730 | |||
731 | pathBegin = (float)_pbs.PathBegin * 2.0e-5f; | ||
732 | pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; | ||
733 | volume *= (pathEnd - pathBegin); | ||
734 | |||
735 | // this is crude aproximation | ||
736 | profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; | ||
737 | profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; | ||
738 | volume *= (profileEnd - profileBegin); | ||
739 | |||
740 | returnMass = m_density * volume; | ||
741 | |||
742 | if (returnMass <= 0) | ||
743 | returnMass = 0.0001f;//ckrinke: Mass must be greater then zero. | ||
744 | // else if (returnMass > _parent_scene.maximumMassObject) | ||
745 | // returnMass = _parent_scene.maximumMassObject; | ||
746 | |||
747 | // Recursively calculate mass | ||
748 | bool HasChildPrim = false; | ||
749 | lock (childrenPrim) | ||
750 | { | ||
751 | if (childrenPrim.Count > 0) | ||
752 | { | ||
753 | HasChildPrim = true; | ||
754 | } | ||
755 | } | ||
756 | |||
757 | if (HasChildPrim) | ||
758 | { | ||
759 | OdePrim[] childPrimArr = new OdePrim[0]; | ||
760 | |||
761 | lock (childrenPrim) | ||
762 | childPrimArr = childrenPrim.ToArray(); | ||
763 | |||
764 | for (int i = 0; i < childPrimArr.Length; i++) | ||
765 | { | ||
766 | if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove) | ||
767 | returnMass += childPrimArr[i].CalculateMass(); | ||
768 | // failsafe, this shouldn't happen but with OpenSim, you never know :) | ||
769 | if (i > 256) | ||
770 | break; | ||
771 | } | ||
772 | } | ||
773 | |||
774 | if (returnMass > _parent_scene.maximumMassObject) | ||
775 | returnMass = _parent_scene.maximumMassObject; | ||
776 | |||
777 | return returnMass; | ||
778 | } | ||
779 | |||
780 | #endregion | ||
781 | |||
782 | private void setMass() | ||
783 | { | ||
784 | if (Body != (IntPtr) 0) | ||
785 | { | ||
786 | float newmass = CalculateMass(); | ||
787 | |||
788 | //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString()); | ||
789 | |||
790 | d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z); | ||
791 | d.BodySetMass(Body, ref pMass); | ||
792 | } | ||
793 | } | ||
794 | |||
795 | private void setAngularVelocity(float x, float y, float z) | ||
796 | { | ||
797 | if (Body != (IntPtr)0) | ||
798 | { | ||
799 | d.BodySetAngularVel(Body, x, y, z); | ||
800 | } | ||
801 | } | ||
802 | |||
803 | /// <summary> | ||
804 | /// Stop a prim from being subject to physics. | ||
805 | /// </summary> | ||
806 | internal void disableBody() | ||
807 | { | ||
808 | //this kills the body so things like 'mesh' can re-create it. | ||
809 | lock (this) | ||
810 | { | ||
811 | if (!childPrim) | ||
812 | { | ||
813 | if (Body != IntPtr.Zero) | ||
814 | { | ||
815 | _parent_scene.DeactivatePrim(this); | ||
816 | m_collisionCategories &= ~CollisionCategories.Body; | ||
817 | m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); | ||
818 | |||
819 | if (m_assetFailed) | ||
820 | { | ||
821 | d.GeomSetCategoryBits(prim_geom, 0); | ||
822 | d.GeomSetCollideBits(prim_geom, 0); | ||
823 | } | ||
824 | else | ||
825 | { | ||
826 | d.GeomSetCategoryBits(prim_geom, (uint)m_collisionCategories); | ||
827 | d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); | ||
828 | } | ||
829 | |||
830 | d.BodyDestroy(Body); | ||
831 | lock (childrenPrim) | ||
832 | { | ||
833 | if (childrenPrim.Count > 0) | ||
834 | { | ||
835 | foreach (OdePrim prm in childrenPrim) | ||
836 | { | ||
837 | _parent_scene.DeactivatePrim(prm); | ||
838 | prm.Body = IntPtr.Zero; | ||
839 | } | ||
840 | } | ||
841 | } | ||
842 | Body = IntPtr.Zero; | ||
843 | } | ||
844 | } | ||
845 | else | ||
846 | { | ||
847 | _parent_scene.DeactivatePrim(this); | ||
848 | |||
849 | m_collisionCategories &= ~CollisionCategories.Body; | ||
850 | m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); | ||
851 | |||
852 | if (m_assetFailed) | ||
853 | { | ||
854 | d.GeomSetCategoryBits(prim_geom, 0); | ||
855 | d.GeomSetCollideBits(prim_geom, 0); | ||
856 | } | ||
857 | else | ||
858 | { | ||
859 | |||
860 | d.GeomSetCategoryBits(prim_geom, (uint)m_collisionCategories); | ||
861 | d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); | ||
862 | } | ||
863 | |||
864 | Body = IntPtr.Zero; | ||
865 | } | ||
866 | } | ||
867 | |||
868 | m_disabled = true; | ||
869 | m_collisionscore = 0; | ||
870 | } | ||
871 | |||
872 | private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>(); | ||
873 | |||
874 | private void setMesh(OdeScene parent_scene, IMesh mesh) | ||
875 | { | ||
876 | // m_log.DebugFormat("[ODE PRIM]: Setting mesh on {0} to {1}", Name, mesh); | ||
877 | |||
878 | // This sleeper is there to moderate how long it takes between | ||
879 | // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object | ||
880 | |||
881 | //Thread.Sleep(10); | ||
882 | |||
883 | //Kill Body so that mesh can re-make the geom | ||
884 | if (IsPhysical && Body != IntPtr.Zero) | ||
885 | { | ||
886 | if (childPrim) | ||
887 | { | ||
888 | if (_parent != null) | ||
889 | { | ||
890 | OdePrim parent = (OdePrim)_parent; | ||
891 | parent.ChildDelink(this); | ||
892 | } | ||
893 | } | ||
894 | else | ||
895 | { | ||
896 | disableBody(); | ||
897 | } | ||
898 | } | ||
899 | |||
900 | IntPtr vertices, indices; | ||
901 | int vertexCount, indexCount; | ||
902 | int vertexStride, triStride; | ||
903 | mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap | ||
904 | mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage | ||
905 | m_expectedCollisionContacts = indexCount; | ||
906 | mesh.releaseSourceMeshData(); // free up the original mesh data to save memory | ||
907 | |||
908 | // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at | ||
909 | // the same time. | ||
910 | lock (m_MeshToTriMeshMap) | ||
911 | { | ||
912 | if (m_MeshToTriMeshMap.ContainsKey(mesh)) | ||
913 | { | ||
914 | _triMeshData = m_MeshToTriMeshMap[mesh]; | ||
915 | } | ||
916 | else | ||
917 | { | ||
918 | _triMeshData = d.GeomTriMeshDataCreate(); | ||
919 | |||
920 | d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); | ||
921 | d.GeomTriMeshDataPreprocess(_triMeshData); | ||
922 | m_MeshToTriMeshMap[mesh] = _triMeshData; | ||
923 | } | ||
924 | } | ||
925 | |||
926 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
927 | try | ||
928 | { | ||
929 | SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, null, null, null)); | ||
930 | } | ||
931 | catch (AccessViolationException) | ||
932 | { | ||
933 | m_log.ErrorFormat("[PHYSICS]: MESH LOCKED FOR {0}", Name); | ||
934 | return; | ||
935 | } | ||
936 | |||
937 | // if (IsPhysical && Body == (IntPtr) 0) | ||
938 | // { | ||
939 | // Recreate the body | ||
940 | // m_interpenetrationcount = 0; | ||
941 | // m_collisionscore = 0; | ||
942 | |||
943 | // enableBody(); | ||
944 | // } | ||
945 | } | ||
946 | |||
947 | internal void ProcessTaints() | ||
948 | { | ||
949 | #if SPAM | ||
950 | Console.WriteLine("ZProcessTaints for " + Name); | ||
951 | #endif | ||
952 | |||
953 | // This must be processed as the very first taint so that later operations have a prim_geom to work with | ||
954 | // if this is a new prim. | ||
955 | if (m_taintadd) | ||
956 | changeadd(); | ||
957 | |||
958 | if (!_position.ApproxEquals(m_taintposition, 0f)) | ||
959 | changemove(); | ||
960 | |||
961 | if (m_taintrot != _orientation) | ||
962 | { | ||
963 | if (childPrim && IsPhysical) // For physical child prim... | ||
964 | { | ||
965 | rotate(); | ||
966 | // KF: ODE will also rotate the parent prim! | ||
967 | // so rotate the root back to where it was | ||
968 | OdePrim parent = (OdePrim)_parent; | ||
969 | parent.rotate(); | ||
970 | } | ||
971 | else | ||
972 | { | ||
973 | //Just rotate the prim | ||
974 | rotate(); | ||
975 | } | ||
976 | } | ||
977 | |||
978 | if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent)) | ||
979 | changePhysicsStatus(); | ||
980 | |||
981 | if (!_size.ApproxEquals(m_taintsize, 0f)) | ||
982 | changesize(); | ||
983 | |||
984 | if (m_taintshape) | ||
985 | changeshape(); | ||
986 | |||
987 | if (m_taintforce) | ||
988 | changeAddForce(); | ||
989 | |||
990 | if (m_taintaddangularforce) | ||
991 | changeAddAngularForce(); | ||
992 | |||
993 | if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) | ||
994 | changeSetTorque(); | ||
995 | |||
996 | if (m_taintdisable) | ||
997 | changedisable(); | ||
998 | |||
999 | if (m_taintselected != m_isSelected) | ||
1000 | changeSelectedStatus(); | ||
1001 | |||
1002 | if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) | ||
1003 | changevelocity(); | ||
1004 | |||
1005 | if (m_taintparent != _parent) | ||
1006 | changelink(); | ||
1007 | |||
1008 | if (m_taintCollidesWater != m_collidesWater) | ||
1009 | changefloatonwater(); | ||
1010 | |||
1011 | if (m_taintAngularLock != m_angularlock) | ||
1012 | changeAngularLock(); | ||
1013 | } | ||
1014 | |||
1015 | /// <summary> | ||
1016 | /// Change prim in response to an angular lock taint. | ||
1017 | /// </summary> | ||
1018 | private void changeAngularLock() | ||
1019 | { | ||
1020 | // do we have a Physical object? | ||
1021 | if (Body != IntPtr.Zero) | ||
1022 | { | ||
1023 | //Check that we have a Parent | ||
1024 | //If we have a parent then we're not authorative here | ||
1025 | if (_parent == null) | ||
1026 | { | ||
1027 | if (m_taintAngularLock != 0) | ||
1028 | { | ||
1029 | createAMotor(m_taintAngularLock); | ||
1030 | } | ||
1031 | else | ||
1032 | { | ||
1033 | if (Amotor != IntPtr.Zero) | ||
1034 | { | ||
1035 | d.JointDestroy(Amotor); | ||
1036 | Amotor = IntPtr.Zero; | ||
1037 | } | ||
1038 | } | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | m_angularlock = m_taintAngularLock; | ||
1043 | } | ||
1044 | |||
1045 | /// <summary> | ||
1046 | /// Change prim in response to a link taint. | ||
1047 | /// </summary> | ||
1048 | private void changelink() | ||
1049 | { | ||
1050 | // If the newly set parent is not null | ||
1051 | // create link | ||
1052 | if (_parent == null && m_taintparent != null) | ||
1053 | { | ||
1054 | if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim) | ||
1055 | { | ||
1056 | OdePrim obj = (OdePrim)m_taintparent; | ||
1057 | //obj.disableBody(); | ||
1058 | //Console.WriteLine("changelink calls ParentPrim"); | ||
1059 | obj.AddChildPrim(this); | ||
1060 | |||
1061 | /* | ||
1062 | if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body) | ||
1063 | { | ||
1064 | _linkJointGroup = d.JointGroupCreate(0); | ||
1065 | m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup); | ||
1066 | d.JointAttach(m_linkJoint, obj.Body, Body); | ||
1067 | d.JointSetFixed(m_linkJoint); | ||
1068 | } | ||
1069 | */ | ||
1070 | } | ||
1071 | } | ||
1072 | // If the newly set parent is null | ||
1073 | // destroy link | ||
1074 | else if (_parent != null && m_taintparent == null) | ||
1075 | { | ||
1076 | //Console.WriteLine(" changelink B"); | ||
1077 | |||
1078 | if (_parent is OdePrim) | ||
1079 | { | ||
1080 | OdePrim obj = (OdePrim)_parent; | ||
1081 | obj.ChildDelink(this); | ||
1082 | childPrim = false; | ||
1083 | //_parent = null; | ||
1084 | } | ||
1085 | |||
1086 | /* | ||
1087 | if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0) | ||
1088 | d.JointGroupDestroy(_linkJointGroup); | ||
1089 | |||
1090 | _linkJointGroup = (IntPtr)0; | ||
1091 | m_linkJoint = (IntPtr)0; | ||
1092 | */ | ||
1093 | } | ||
1094 | |||
1095 | _parent = m_taintparent; | ||
1096 | m_taintPhysics = IsPhysical; | ||
1097 | } | ||
1098 | |||
1099 | /// <summary> | ||
1100 | /// Add a child prim to this parent prim. | ||
1101 | /// </summary> | ||
1102 | /// <param name="prim">Child prim</param> | ||
1103 | private void AddChildPrim(OdePrim prim) | ||
1104 | { | ||
1105 | if (LocalID == prim.LocalID) | ||
1106 | return; | ||
1107 | |||
1108 | if (Body == IntPtr.Zero) | ||
1109 | { | ||
1110 | Body = d.BodyCreate(_parent_scene.world); | ||
1111 | setMass(); | ||
1112 | } | ||
1113 | |||
1114 | lock (childrenPrim) | ||
1115 | { | ||
1116 | if (childrenPrim.Contains(prim)) | ||
1117 | return; | ||
1118 | |||
1119 | // m_log.DebugFormat( | ||
1120 | // "[ODE PRIM]: Linking prim {0} {1} to {2} {3}", prim.Name, prim.LocalID, Name, LocalID); | ||
1121 | |||
1122 | childrenPrim.Add(prim); | ||
1123 | |||
1124 | foreach (OdePrim prm in childrenPrim) | ||
1125 | { | ||
1126 | d.Mass m2; | ||
1127 | d.MassSetZero(out m2); | ||
1128 | d.MassSetBoxTotal(out m2, prm.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); | ||
1129 | |||
1130 | d.Quaternion quat = new d.Quaternion(); | ||
1131 | quat.W = prm._orientation.W; | ||
1132 | quat.X = prm._orientation.X; | ||
1133 | quat.Y = prm._orientation.Y; | ||
1134 | quat.Z = prm._orientation.Z; | ||
1135 | |||
1136 | d.Matrix3 mat = new d.Matrix3(); | ||
1137 | d.RfromQ(out mat, ref quat); | ||
1138 | d.MassRotate(ref m2, ref mat); | ||
1139 | d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z); | ||
1140 | d.MassAdd(ref pMass, ref m2); | ||
1141 | } | ||
1142 | |||
1143 | foreach (OdePrim prm in childrenPrim) | ||
1144 | { | ||
1145 | prm.m_collisionCategories |= CollisionCategories.Body; | ||
1146 | prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); | ||
1147 | |||
1148 | //Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name); | ||
1149 | if (prm.m_assetFailed) | ||
1150 | { | ||
1151 | d.GeomSetCategoryBits(prm.prim_geom, 0); | ||
1152 | d.GeomSetCollideBits(prm.prim_geom, (uint)prm.BadMeshAssetCollideBits); | ||
1153 | } | ||
1154 | else | ||
1155 | { | ||
1156 | d.GeomSetCategoryBits(prm.prim_geom, (uint)prm.m_collisionCategories); | ||
1157 | d.GeomSetCollideBits(prm.prim_geom, (uint)prm.m_collisionFlags); | ||
1158 | } | ||
1159 | |||
1160 | d.Quaternion quat = new d.Quaternion(); | ||
1161 | quat.W = prm._orientation.W; | ||
1162 | quat.X = prm._orientation.X; | ||
1163 | quat.Y = prm._orientation.Y; | ||
1164 | quat.Z = prm._orientation.Z; | ||
1165 | |||
1166 | d.Matrix3 mat = new d.Matrix3(); | ||
1167 | d.RfromQ(out mat, ref quat); | ||
1168 | if (Body != IntPtr.Zero) | ||
1169 | { | ||
1170 | d.GeomSetBody(prm.prim_geom, Body); | ||
1171 | prm.childPrim = true; | ||
1172 | d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z); | ||
1173 | //d.GeomSetOffsetPosition(prim.prim_geom, | ||
1174 | // (Position.X - prm.Position.X) - pMass.c.X, | ||
1175 | // (Position.Y - prm.Position.Y) - pMass.c.Y, | ||
1176 | // (Position.Z - prm.Position.Z) - pMass.c.Z); | ||
1177 | d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); | ||
1178 | //d.GeomSetOffsetRotation(prm.prim_geom, ref mat); | ||
1179 | d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); | ||
1180 | d.BodySetMass(Body, ref pMass); | ||
1181 | } | ||
1182 | else | ||
1183 | { | ||
1184 | m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name); | ||
1185 | } | ||
1186 | |||
1187 | prm.m_interpenetrationcount = 0; | ||
1188 | prm.m_collisionscore = 0; | ||
1189 | prm.m_disabled = false; | ||
1190 | |||
1191 | prm.Body = Body; | ||
1192 | _parent_scene.ActivatePrim(prm); | ||
1193 | } | ||
1194 | |||
1195 | m_collisionCategories |= CollisionCategories.Body; | ||
1196 | m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); | ||
1197 | |||
1198 | if (m_assetFailed) | ||
1199 | { | ||
1200 | d.GeomSetCategoryBits(prim_geom, 0); | ||
1201 | d.GeomSetCollideBits(prim_geom, (uint)BadMeshAssetCollideBits); | ||
1202 | } | ||
1203 | else | ||
1204 | { | ||
1205 | //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name); | ||
1206 | d.GeomSetCategoryBits(prim_geom, (uint)m_collisionCategories); | ||
1207 | //Console.WriteLine(" Post GeomSetCategoryBits 2"); | ||
1208 | d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); | ||
1209 | } | ||
1210 | |||
1211 | d.Quaternion quat2 = new d.Quaternion(); | ||
1212 | quat2.W = _orientation.W; | ||
1213 | quat2.X = _orientation.X; | ||
1214 | quat2.Y = _orientation.Y; | ||
1215 | quat2.Z = _orientation.Z; | ||
1216 | |||
1217 | d.Matrix3 mat2 = new d.Matrix3(); | ||
1218 | d.RfromQ(out mat2, ref quat2); | ||
1219 | d.GeomSetBody(prim_geom, Body); | ||
1220 | d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z); | ||
1221 | //d.GeomSetOffsetPosition(prim.prim_geom, | ||
1222 | // (Position.X - prm.Position.X) - pMass.c.X, | ||
1223 | // (Position.Y - prm.Position.Y) - pMass.c.Y, | ||
1224 | // (Position.Z - prm.Position.Z) - pMass.c.Z); | ||
1225 | //d.GeomSetOffsetRotation(prim_geom, ref mat2); | ||
1226 | d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); | ||
1227 | d.BodySetMass(Body, ref pMass); | ||
1228 | |||
1229 | d.BodySetAutoDisableFlag(Body, true); | ||
1230 | d.BodySetAutoDisableSteps(Body, body_autodisable_frames); | ||
1231 | |||
1232 | m_interpenetrationcount = 0; | ||
1233 | m_collisionscore = 0; | ||
1234 | m_disabled = false; | ||
1235 | |||
1236 | // The body doesn't already have a finite rotation mode set here | ||
1237 | // or remove | ||
1238 | if (_parent == null) | ||
1239 | { | ||
1240 | createAMotor(m_angularlock); | ||
1241 | } | ||
1242 | |||
1243 | d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); | ||
1244 | |||
1245 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
1246 | m_vehicle.Enable(Body, _parent_scene); | ||
1247 | |||
1248 | _parent_scene.ActivatePrim(this); | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | private void ChildSetGeom(OdePrim odePrim) | ||
1253 | { | ||
1254 | // m_log.DebugFormat( | ||
1255 | // "[ODE PRIM]: ChildSetGeom {0} {1} for {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); | ||
1256 | |||
1257 | //if (IsPhysical && Body != IntPtr.Zero) | ||
1258 | lock (childrenPrim) | ||
1259 | { | ||
1260 | foreach (OdePrim prm in childrenPrim) | ||
1261 | { | ||
1262 | //prm.childPrim = true; | ||
1263 | prm.disableBody(); | ||
1264 | //prm.m_taintparent = null; | ||
1265 | //prm._parent = null; | ||
1266 | //prm.m_taintPhysics = false; | ||
1267 | //prm.m_disabled = true; | ||
1268 | //prm.childPrim = false; | ||
1269 | } | ||
1270 | } | ||
1271 | |||
1272 | disableBody(); | ||
1273 | |||
1274 | // Spurious - Body == IntPtr.Zero after disableBody() | ||
1275 | // if (Body != IntPtr.Zero) | ||
1276 | // { | ||
1277 | // _parent_scene.DeactivatePrim(this); | ||
1278 | // } | ||
1279 | |||
1280 | lock (childrenPrim) | ||
1281 | { | ||
1282 | foreach (OdePrim prm in childrenPrim) | ||
1283 | { | ||
1284 | //Console.WriteLine("ChildSetGeom calls ParentPrim"); | ||
1285 | AddChildPrim(prm); | ||
1286 | } | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | private void ChildDelink(OdePrim odePrim) | ||
1291 | { | ||
1292 | // m_log.DebugFormat( | ||
1293 | // "[ODE PRIM]: Delinking prim {0} {1} from {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); | ||
1294 | |||
1295 | // Okay, we have a delinked child.. need to rebuild the body. | ||
1296 | lock (childrenPrim) | ||
1297 | { | ||
1298 | foreach (OdePrim prm in childrenPrim) | ||
1299 | { | ||
1300 | prm.childPrim = true; | ||
1301 | prm.disableBody(); | ||
1302 | //prm.m_taintparent = null; | ||
1303 | //prm._parent = null; | ||
1304 | //prm.m_taintPhysics = false; | ||
1305 | //prm.m_disabled = true; | ||
1306 | //prm.childPrim = false; | ||
1307 | } | ||
1308 | } | ||
1309 | |||
1310 | disableBody(); | ||
1311 | |||
1312 | lock (childrenPrim) | ||
1313 | { | ||
1314 | //Console.WriteLine("childrenPrim.Remove " + odePrim); | ||
1315 | childrenPrim.Remove(odePrim); | ||
1316 | } | ||
1317 | |||
1318 | // Spurious - Body == IntPtr.Zero after disableBody() | ||
1319 | // if (Body != IntPtr.Zero) | ||
1320 | // { | ||
1321 | // _parent_scene.DeactivatePrim(this); | ||
1322 | // } | ||
1323 | |||
1324 | lock (childrenPrim) | ||
1325 | { | ||
1326 | foreach (OdePrim prm in childrenPrim) | ||
1327 | { | ||
1328 | //Console.WriteLine("ChildDelink calls ParentPrim"); | ||
1329 | AddChildPrim(prm); | ||
1330 | } | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | /// <summary> | ||
1335 | /// Change prim in response to a selection taint. | ||
1336 | /// </summary> | ||
1337 | private void changeSelectedStatus() | ||
1338 | { | ||
1339 | if (m_taintselected) | ||
1340 | { | ||
1341 | m_collisionCategories = CollisionCategories.Selected; | ||
1342 | m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space); | ||
1343 | |||
1344 | // We do the body disable soft twice because 'in theory' a collision could have happened | ||
1345 | // in between the disabling and the collision properties setting | ||
1346 | // which would wake the physical body up from a soft disabling and potentially cause it to fall | ||
1347 | // through the ground. | ||
1348 | |||
1349 | // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select | ||
1350 | // just one part of the assembly, the rest of the assembly is non-selected and still simulating, | ||
1351 | // so that causes the selected part to wake up and continue moving. | ||
1352 | |||
1353 | // even if you select all parts of a jointed assembly, it is not guaranteed that the entire | ||
1354 | // assembly will stop simulating during the selection, because of the lack of atomicity | ||
1355 | // of select operations (their processing could be interrupted by a thread switch, causing | ||
1356 | // simulation to continue before all of the selected object notifications trickle down to | ||
1357 | // the physics engine). | ||
1358 | |||
1359 | // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are | ||
1360 | // selected and disabled. then, due to a thread switch, the selection processing is | ||
1361 | // interrupted and the physics engine continues to simulate, so the last 50 items, whose | ||
1362 | // selection was not yet processed, continues to simulate. this wakes up ALL of the | ||
1363 | // first 50 again. then the last 50 are disabled. then the first 50, which were just woken | ||
1364 | // up, start simulating again, which in turn wakes up the last 50. | ||
1365 | |||
1366 | if (IsPhysical) | ||
1367 | { | ||
1368 | disableBodySoft(); | ||
1369 | } | ||
1370 | |||
1371 | if (m_assetFailed) | ||
1372 | { | ||
1373 | d.GeomSetCategoryBits(prim_geom, 0); | ||
1374 | d.GeomSetCollideBits(prim_geom, 0); | ||
1375 | } | ||
1376 | else | ||
1377 | { | ||
1378 | d.GeomSetCategoryBits(prim_geom, (uint)m_collisionCategories); | ||
1379 | d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); | ||
1380 | } | ||
1381 | |||
1382 | if (IsPhysical) | ||
1383 | { | ||
1384 | disableBodySoft(); | ||
1385 | } | ||
1386 | } | ||
1387 | else | ||
1388 | { | ||
1389 | m_collisionCategories = CollisionCategories.Geom; | ||
1390 | |||
1391 | if (IsPhysical) | ||
1392 | m_collisionCategories |= CollisionCategories.Body; | ||
1393 | |||
1394 | m_collisionFlags = m_default_collisionFlags; | ||
1395 | |||
1396 | if (m_collidesLand) | ||
1397 | m_collisionFlags |= CollisionCategories.Land; | ||
1398 | if (m_collidesWater) | ||
1399 | m_collisionFlags |= CollisionCategories.Water; | ||
1400 | |||
1401 | if (m_assetFailed) | ||
1402 | { | ||
1403 | d.GeomSetCategoryBits(prim_geom, 0); | ||
1404 | d.GeomSetCollideBits(prim_geom, (uint)BadMeshAssetCollideBits); | ||
1405 | } | ||
1406 | else | ||
1407 | { | ||
1408 | d.GeomSetCategoryBits(prim_geom, (uint)m_collisionCategories); | ||
1409 | d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); | ||
1410 | } | ||
1411 | |||
1412 | if (IsPhysical) | ||
1413 | { | ||
1414 | if (Body != IntPtr.Zero) | ||
1415 | { | ||
1416 | d.BodySetLinearVel(Body, 0f, 0f, 0f); | ||
1417 | d.BodySetForce(Body, 0, 0, 0); | ||
1418 | enableBodySoft(); | ||
1419 | } | ||
1420 | } | ||
1421 | } | ||
1422 | |||
1423 | resetCollisionAccounting(); | ||
1424 | m_isSelected = m_taintselected; | ||
1425 | }//end changeSelectedStatus | ||
1426 | |||
1427 | internal void ResetTaints() | ||
1428 | { | ||
1429 | m_taintposition = _position; | ||
1430 | m_taintrot = _orientation; | ||
1431 | m_taintPhysics = IsPhysical; | ||
1432 | m_taintselected = m_isSelected; | ||
1433 | m_taintsize = _size; | ||
1434 | m_taintshape = false; | ||
1435 | m_taintforce = false; | ||
1436 | m_taintdisable = false; | ||
1437 | m_taintVelocity = Vector3.Zero; | ||
1438 | } | ||
1439 | |||
1440 | /// <summary> | ||
1441 | /// Create a geometry for the given mesh in the given target space. | ||
1442 | /// </summary> | ||
1443 | /// <param name="m_targetSpace"></param> | ||
1444 | /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param> | ||
1445 | private void CreateGeom(IntPtr m_targetSpace, IMesh mesh) | ||
1446 | { | ||
1447 | #if SPAM | ||
1448 | Console.WriteLine("CreateGeom:"); | ||
1449 | #endif | ||
1450 | if (mesh != null) | ||
1451 | { | ||
1452 | setMesh(_parent_scene, mesh); | ||
1453 | } | ||
1454 | else | ||
1455 | { | ||
1456 | if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) | ||
1457 | { | ||
1458 | if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) | ||
1459 | { | ||
1460 | if (((_size.X / 2f) > 0f)) | ||
1461 | { | ||
1462 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1463 | try | ||
1464 | { | ||
1465 | //Console.WriteLine(" CreateGeom 1"); | ||
1466 | SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2)); | ||
1467 | m_expectedCollisionContacts = 3; | ||
1468 | } | ||
1469 | catch (AccessViolationException) | ||
1470 | { | ||
1471 | m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); | ||
1472 | return; | ||
1473 | } | ||
1474 | } | ||
1475 | else | ||
1476 | { | ||
1477 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1478 | try | ||
1479 | { | ||
1480 | //Console.WriteLine(" CreateGeom 2"); | ||
1481 | SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); | ||
1482 | m_expectedCollisionContacts = 4; | ||
1483 | } | ||
1484 | catch (AccessViolationException) | ||
1485 | { | ||
1486 | m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); | ||
1487 | return; | ||
1488 | } | ||
1489 | } | ||
1490 | } | ||
1491 | else | ||
1492 | { | ||
1493 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1494 | try | ||
1495 | { | ||
1496 | //Console.WriteLine(" CreateGeom 3"); | ||
1497 | SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); | ||
1498 | m_expectedCollisionContacts = 4; | ||
1499 | } | ||
1500 | catch (AccessViolationException) | ||
1501 | { | ||
1502 | m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); | ||
1503 | return; | ||
1504 | } | ||
1505 | } | ||
1506 | } | ||
1507 | else | ||
1508 | { | ||
1509 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1510 | try | ||
1511 | { | ||
1512 | //Console.WriteLine(" CreateGeom 4"); | ||
1513 | SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); | ||
1514 | m_expectedCollisionContacts = 4; | ||
1515 | } | ||
1516 | catch (AccessViolationException) | ||
1517 | { | ||
1518 | m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); | ||
1519 | return; | ||
1520 | } | ||
1521 | } | ||
1522 | } | ||
1523 | } | ||
1524 | |||
1525 | /// <summary> | ||
1526 | /// Remove the existing geom from this prim. | ||
1527 | /// </summary> | ||
1528 | /// <param name="m_targetSpace"></param> | ||
1529 | /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param> | ||
1530 | /// <returns>true if the geom was successfully removed, false if it was already gone or the remove failed.</returns> | ||
1531 | internal bool RemoveGeom() | ||
1532 | { | ||
1533 | if (prim_geom != IntPtr.Zero) | ||
1534 | { | ||
1535 | try | ||
1536 | { | ||
1537 | _parent_scene.geom_name_map.Remove(prim_geom); | ||
1538 | _parent_scene.actor_name_map.Remove(prim_geom); | ||
1539 | d.GeomDestroy(prim_geom); | ||
1540 | m_expectedCollisionContacts = 0; | ||
1541 | prim_geom = IntPtr.Zero; | ||
1542 | } | ||
1543 | catch (System.AccessViolationException) | ||
1544 | { | ||
1545 | prim_geom = IntPtr.Zero; | ||
1546 | m_expectedCollisionContacts = 0; | ||
1547 | m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); | ||
1548 | |||
1549 | return false; | ||
1550 | } | ||
1551 | |||
1552 | return true; | ||
1553 | } | ||
1554 | else | ||
1555 | { | ||
1556 | m_log.WarnFormat( | ||
1557 | "[ODE PRIM]: Called RemoveGeom() on {0} {1} where geometry was already null.", Name, LocalID); | ||
1558 | |||
1559 | return false; | ||
1560 | } | ||
1561 | } | ||
1562 | /// <summary> | ||
1563 | /// Add prim in response to an add taint. | ||
1564 | /// </summary> | ||
1565 | private void changeadd() | ||
1566 | { | ||
1567 | // m_log.DebugFormat("[ODE PRIM]: Adding prim {0}", Name); | ||
1568 | |||
1569 | int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position); | ||
1570 | IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position); | ||
1571 | |||
1572 | if (targetspace == IntPtr.Zero) | ||
1573 | targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); | ||
1574 | |||
1575 | m_targetSpace = targetspace; | ||
1576 | |||
1577 | IMesh mesh = null; | ||
1578 | |||
1579 | if (_parent_scene.needsMeshing(_pbs)) | ||
1580 | { | ||
1581 | // Don't need to re-enable body.. it's done in SetMesh | ||
1582 | mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); | ||
1583 | // createmesh returns null when it's a shape that isn't a cube. | ||
1584 | // m_log.Debug(m_localID); | ||
1585 | if (mesh == null) | ||
1586 | CheckMeshAsset(); | ||
1587 | else | ||
1588 | m_assetFailed = false; | ||
1589 | } | ||
1590 | |||
1591 | #if SPAM | ||
1592 | Console.WriteLine("changeadd 1"); | ||
1593 | #endif | ||
1594 | CreateGeom(m_targetSpace, mesh); | ||
1595 | |||
1596 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | ||
1597 | d.Quaternion myrot = new d.Quaternion(); | ||
1598 | myrot.X = _orientation.X; | ||
1599 | myrot.Y = _orientation.Y; | ||
1600 | myrot.Z = _orientation.Z; | ||
1601 | myrot.W = _orientation.W; | ||
1602 | d.GeomSetQuaternion(prim_geom, ref myrot); | ||
1603 | |||
1604 | if (IsPhysical && Body == IntPtr.Zero) | ||
1605 | enableBody(); | ||
1606 | |||
1607 | changeSelectedStatus(); | ||
1608 | |||
1609 | m_taintadd = false; | ||
1610 | } | ||
1611 | |||
1612 | /// <summary> | ||
1613 | /// Move prim in response to a move taint. | ||
1614 | /// </summary> | ||
1615 | private void changemove() | ||
1616 | { | ||
1617 | if (IsPhysical) | ||
1618 | { | ||
1619 | if (!m_disabled && !m_taintremove && !childPrim) | ||
1620 | { | ||
1621 | if (Body == IntPtr.Zero) | ||
1622 | enableBody(); | ||
1623 | |||
1624 | //Prim auto disable after 20 frames, | ||
1625 | //if you move it, re-enable the prim manually. | ||
1626 | if (_parent != null) | ||
1627 | { | ||
1628 | if (m_linkJoint != IntPtr.Zero) | ||
1629 | { | ||
1630 | d.JointDestroy(m_linkJoint); | ||
1631 | m_linkJoint = IntPtr.Zero; | ||
1632 | } | ||
1633 | } | ||
1634 | |||
1635 | if (Body != IntPtr.Zero) | ||
1636 | { | ||
1637 | d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); | ||
1638 | |||
1639 | if (_parent != null) | ||
1640 | { | ||
1641 | OdePrim odParent = (OdePrim)_parent; | ||
1642 | if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body) | ||
1643 | { | ||
1644 | // KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used?? | ||
1645 | Console.WriteLine(" JointCreateFixed"); | ||
1646 | m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup); | ||
1647 | d.JointAttach(m_linkJoint, Body, odParent.Body); | ||
1648 | d.JointSetFixed(m_linkJoint); | ||
1649 | } | ||
1650 | } | ||
1651 | d.BodyEnable(Body); | ||
1652 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
1653 | { | ||
1654 | m_vehicle.Enable(Body, _parent_scene); | ||
1655 | } | ||
1656 | } | ||
1657 | else | ||
1658 | { | ||
1659 | m_log.WarnFormat("[PHYSICS]: Body for {0} still null after enableBody(). This is a crash scenario.", Name); | ||
1660 | } | ||
1661 | } | ||
1662 | //else | ||
1663 | // { | ||
1664 | //m_log.Debug("[BUG]: race!"); | ||
1665 | //} | ||
1666 | } | ||
1667 | |||
1668 | // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); | ||
1669 | // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position); | ||
1670 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1671 | |||
1672 | IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace); | ||
1673 | m_targetSpace = tempspace; | ||
1674 | |||
1675 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1676 | |||
1677 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | ||
1678 | |||
1679 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1680 | d.SpaceAdd(m_targetSpace, prim_geom); | ||
1681 | |||
1682 | changeSelectedStatus(); | ||
1683 | |||
1684 | resetCollisionAccounting(); | ||
1685 | m_taintposition = _position; | ||
1686 | } | ||
1687 | |||
1688 | internal void Move(float timestep) | ||
1689 | { | ||
1690 | float fx = 0; | ||
1691 | float fy = 0; | ||
1692 | float fz = 0; | ||
1693 | |||
1694 | if (outofBounds) | ||
1695 | return; | ||
1696 | |||
1697 | if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // KF: Only move root prims. | ||
1698 | { | ||
1699 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
1700 | { | ||
1701 | // 'VEHICLES' are dealt with in ODEDynamics.cs | ||
1702 | m_vehicle.Step(timestep, _parent_scene); | ||
1703 | } | ||
1704 | else | ||
1705 | { | ||
1706 | //Console.WriteLine("Move " + Name); | ||
1707 | if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009 | ||
1708 | |||
1709 | float m_mass = CalculateMass(); | ||
1710 | |||
1711 | // fz = 0f; | ||
1712 | //m_log.Info(m_collisionFlags.ToString()); | ||
1713 | |||
1714 | |||
1715 | //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle. | ||
1716 | // would come from SceneObjectPart.cs, public void SetBuoyancy(float fvalue) , PhysActor.Buoyancy = fvalue; ?? | ||
1717 | // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up | ||
1718 | // gravityz multiplier = 1 - m_buoyancy | ||
1719 | fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; | ||
1720 | |||
1721 | if (PIDActive) | ||
1722 | { | ||
1723 | //Console.WriteLine("PID " + Name); | ||
1724 | // KF - this is for object move? eg. llSetPos() ? | ||
1725 | //if (!d.BodyIsEnabled(Body)) | ||
1726 | //d.BodySetForce(Body, 0f, 0f, 0f); | ||
1727 | // If we're using the PID controller, then we have no gravity | ||
1728 | //fz = (-1 * _parent_scene.gravityz) * m_mass; //KF: ?? Prims have no global gravity,so simply... | ||
1729 | fz = 0f; | ||
1730 | |||
1731 | // no lock; for now it's only called from within Simulate() | ||
1732 | |||
1733 | // If the PID Controller isn't active then we set our force | ||
1734 | // calculating base velocity to the current position | ||
1735 | |||
1736 | if ((m_PIDTau < 1) && (m_PIDTau != 0)) | ||
1737 | { | ||
1738 | //PID_G = PID_G / m_PIDTau; | ||
1739 | m_PIDTau = 1; | ||
1740 | } | ||
1741 | |||
1742 | if ((PID_G - m_PIDTau) <= 0) | ||
1743 | { | ||
1744 | PID_G = m_PIDTau + 1; | ||
1745 | } | ||
1746 | //PidStatus = true; | ||
1747 | |||
1748 | // PhysicsVector vec = new PhysicsVector(); | ||
1749 | d.Vector3 vel = d.BodyGetLinearVel(Body); | ||
1750 | |||
1751 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
1752 | _target_velocity = | ||
1753 | new Vector3( | ||
1754 | (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep), | ||
1755 | (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep), | ||
1756 | (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep) | ||
1757 | ); | ||
1758 | |||
1759 | // if velocity is zero, use position control; otherwise, velocity control | ||
1760 | |||
1761 | if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f)) | ||
1762 | { | ||
1763 | // keep track of where we stopped. No more slippin' & slidin' | ||
1764 | |||
1765 | // We only want to deactivate the PID Controller if we think we want to have our surrogate | ||
1766 | // react to the physics scene by moving it's position. | ||
1767 | // Avatar to Avatar collisions | ||
1768 | // Prim to avatar collisions | ||
1769 | |||
1770 | //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); | ||
1771 | //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2); | ||
1772 | //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; | ||
1773 | d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z); | ||
1774 | d.BodySetLinearVel(Body, 0, 0, 0); | ||
1775 | d.BodyAddForce(Body, 0, 0, fz); | ||
1776 | return; | ||
1777 | } | ||
1778 | else | ||
1779 | { | ||
1780 | _zeroFlag = false; | ||
1781 | |||
1782 | // We're flying and colliding with something | ||
1783 | fx = ((_target_velocity.X) - vel.X) * (PID_D); | ||
1784 | fy = ((_target_velocity.Y) - vel.Y) * (PID_D); | ||
1785 | |||
1786 | // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; | ||
1787 | |||
1788 | fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass); | ||
1789 | } | ||
1790 | } // end if (PIDActive) | ||
1791 | |||
1792 | // Hover PID Controller needs to be mutually exlusive to MoveTo PID controller | ||
1793 | if (m_useHoverPID && !PIDActive) | ||
1794 | { | ||
1795 | //Console.WriteLine("Hover " + Name); | ||
1796 | |||
1797 | // If we're using the PID controller, then we have no gravity | ||
1798 | fz = (-1 * _parent_scene.gravityz) * m_mass; | ||
1799 | |||
1800 | // no lock; for now it's only called from within Simulate() | ||
1801 | |||
1802 | // If the PID Controller isn't active then we set our force | ||
1803 | // calculating base velocity to the current position | ||
1804 | |||
1805 | if ((m_PIDTau < 1)) | ||
1806 | { | ||
1807 | PID_G = PID_G / m_PIDTau; | ||
1808 | } | ||
1809 | |||
1810 | if ((PID_G - m_PIDTau) <= 0) | ||
1811 | { | ||
1812 | PID_G = m_PIDTau + 1; | ||
1813 | } | ||
1814 | |||
1815 | // Where are we, and where are we headed? | ||
1816 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
1817 | d.Vector3 vel = d.BodyGetLinearVel(Body); | ||
1818 | |||
1819 | // Non-Vehicles have a limited set of Hover options. | ||
1820 | // determine what our target height really is based on HoverType | ||
1821 | switch (m_PIDHoverType) | ||
1822 | { | ||
1823 | case PIDHoverType.Ground: | ||
1824 | m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y); | ||
1825 | m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight; | ||
1826 | break; | ||
1827 | case PIDHoverType.GroundAndWater: | ||
1828 | m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y); | ||
1829 | m_waterHeight = _parent_scene.GetWaterLevel(); | ||
1830 | if (m_groundHeight > m_waterHeight) | ||
1831 | { | ||
1832 | m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight; | ||
1833 | } | ||
1834 | else | ||
1835 | { | ||
1836 | m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight; | ||
1837 | } | ||
1838 | break; | ||
1839 | |||
1840 | } // end switch (m_PIDHoverType) | ||
1841 | |||
1842 | |||
1843 | _target_velocity = | ||
1844 | new Vector3(0.0f, 0.0f, | ||
1845 | (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep) | ||
1846 | ); | ||
1847 | |||
1848 | // if velocity is zero, use position control; otherwise, velocity control | ||
1849 | |||
1850 | if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f)) | ||
1851 | { | ||
1852 | // keep track of where we stopped. No more slippin' & slidin' | ||
1853 | |||
1854 | // We only want to deactivate the PID Controller if we think we want to have our surrogate | ||
1855 | // react to the physics scene by moving it's position. | ||
1856 | // Avatar to Avatar collisions | ||
1857 | // Prim to avatar collisions | ||
1858 | |||
1859 | d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight); | ||
1860 | d.BodySetLinearVel(Body, vel.X, vel.Y, 0); | ||
1861 | d.BodyAddForce(Body, 0, 0, fz); | ||
1862 | return; | ||
1863 | } | ||
1864 | else | ||
1865 | { | ||
1866 | _zeroFlag = false; | ||
1867 | |||
1868 | // We're flying and colliding with something | ||
1869 | fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass); | ||
1870 | } | ||
1871 | } | ||
1872 | |||
1873 | fx *= m_mass; | ||
1874 | fy *= m_mass; | ||
1875 | //fz *= m_mass; | ||
1876 | |||
1877 | fx += m_force.X; | ||
1878 | fy += m_force.Y; | ||
1879 | fz += m_force.Z; | ||
1880 | |||
1881 | //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString()); | ||
1882 | if (fx != 0 || fy != 0 || fz != 0) | ||
1883 | { | ||
1884 | //m_taintdisable = true; | ||
1885 | //base.RaiseOutOfBounds(Position); | ||
1886 | //d.BodySetLinearVel(Body, fx, fy, 0f); | ||
1887 | if (!d.BodyIsEnabled(Body)) | ||
1888 | { | ||
1889 | // A physical body at rest on a surface will auto-disable after a while, | ||
1890 | // this appears to re-enable it incase the surface it is upon vanishes, | ||
1891 | // and the body should fall again. | ||
1892 | d.BodySetLinearVel(Body, 0f, 0f, 0f); | ||
1893 | d.BodySetForce(Body, 0, 0, 0); | ||
1894 | enableBodySoft(); | ||
1895 | } | ||
1896 | |||
1897 | // 35x10 = 350n times the mass per second applied maximum. | ||
1898 | float nmax = 35f * m_mass; | ||
1899 | float nmin = -35f * m_mass; | ||
1900 | |||
1901 | if (fx > nmax) | ||
1902 | fx = nmax; | ||
1903 | if (fx < nmin) | ||
1904 | fx = nmin; | ||
1905 | if (fy > nmax) | ||
1906 | fy = nmax; | ||
1907 | if (fy < nmin) | ||
1908 | fy = nmin; | ||
1909 | d.BodyAddForce(Body, fx, fy, fz); | ||
1910 | //Console.WriteLine("AddForce " + fx + "," + fy + "," + fz); | ||
1911 | } | ||
1912 | } | ||
1913 | } | ||
1914 | else | ||
1915 | { // is not physical, or is not a body or is selected | ||
1916 | // _zeroPosition = d.BodyGetPosition(Body); | ||
1917 | return; | ||
1918 | //Console.WriteLine("Nothing " + Name); | ||
1919 | |||
1920 | } | ||
1921 | } | ||
1922 | |||
1923 | private void rotate() | ||
1924 | { | ||
1925 | d.Quaternion myrot = new d.Quaternion(); | ||
1926 | myrot.X = _orientation.X; | ||
1927 | myrot.Y = _orientation.Y; | ||
1928 | myrot.Z = _orientation.Z; | ||
1929 | myrot.W = _orientation.W; | ||
1930 | if (Body != IntPtr.Zero) | ||
1931 | { | ||
1932 | // KF: If this is a root prim do BodySet | ||
1933 | d.BodySetQuaternion(Body, ref myrot); | ||
1934 | if (IsPhysical) | ||
1935 | { | ||
1936 | // create or remove locks | ||
1937 | createAMotor(m_angularlock); | ||
1938 | } | ||
1939 | } | ||
1940 | else | ||
1941 | { | ||
1942 | // daughter prim, do Geom set | ||
1943 | d.GeomSetQuaternion(prim_geom, ref myrot); | ||
1944 | } | ||
1945 | |||
1946 | resetCollisionAccounting(); | ||
1947 | m_taintrot = _orientation; | ||
1948 | } | ||
1949 | |||
1950 | private void resetCollisionAccounting() | ||
1951 | { | ||
1952 | m_collisionscore = 0; | ||
1953 | m_interpenetrationcount = 0; | ||
1954 | m_disabled = false; | ||
1955 | } | ||
1956 | |||
1957 | /// <summary> | ||
1958 | /// Change prim in response to a disable taint. | ||
1959 | /// </summary> | ||
1960 | private void changedisable() | ||
1961 | { | ||
1962 | m_disabled = true; | ||
1963 | if (Body != IntPtr.Zero) | ||
1964 | { | ||
1965 | d.BodyDisable(Body); | ||
1966 | Body = IntPtr.Zero; | ||
1967 | } | ||
1968 | |||
1969 | m_taintdisable = false; | ||
1970 | } | ||
1971 | |||
1972 | /// <summary> | ||
1973 | /// Change prim in response to a physics status taint | ||
1974 | /// </summary> | ||
1975 | private void changePhysicsStatus() | ||
1976 | { | ||
1977 | if (IsPhysical) | ||
1978 | { | ||
1979 | if (Body == IntPtr.Zero) | ||
1980 | { | ||
1981 | if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) | ||
1982 | { | ||
1983 | changeshape(); | ||
1984 | } | ||
1985 | else | ||
1986 | { | ||
1987 | enableBody(); | ||
1988 | } | ||
1989 | } | ||
1990 | } | ||
1991 | else | ||
1992 | { | ||
1993 | if (Body != IntPtr.Zero) | ||
1994 | { | ||
1995 | if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) | ||
1996 | { | ||
1997 | RemoveGeom(); | ||
1998 | |||
1999 | //Console.WriteLine("changePhysicsStatus for " + Name); | ||
2000 | changeadd(); | ||
2001 | } | ||
2002 | |||
2003 | if (childPrim) | ||
2004 | { | ||
2005 | if (_parent != null) | ||
2006 | { | ||
2007 | OdePrim parent = (OdePrim)_parent; | ||
2008 | parent.ChildDelink(this); | ||
2009 | } | ||
2010 | } | ||
2011 | else | ||
2012 | { | ||
2013 | disableBody(); | ||
2014 | } | ||
2015 | } | ||
2016 | } | ||
2017 | |||
2018 | changeSelectedStatus(); | ||
2019 | |||
2020 | resetCollisionAccounting(); | ||
2021 | m_taintPhysics = IsPhysical; | ||
2022 | } | ||
2023 | |||
2024 | /// <summary> | ||
2025 | /// Change prim in response to a size taint. | ||
2026 | /// </summary> | ||
2027 | private void changesize() | ||
2028 | { | ||
2029 | #if SPAM | ||
2030 | m_log.DebugFormat("[ODE PRIM]: Called changesize"); | ||
2031 | #endif | ||
2032 | |||
2033 | if (_size.X <= 0) _size.X = 0.01f; | ||
2034 | if (_size.Y <= 0) _size.Y = 0.01f; | ||
2035 | if (_size.Z <= 0) _size.Z = 0.01f; | ||
2036 | |||
2037 | //kill body to rebuild | ||
2038 | if (IsPhysical && Body != IntPtr.Zero) | ||
2039 | { | ||
2040 | if (childPrim) | ||
2041 | { | ||
2042 | if (_parent != null) | ||
2043 | { | ||
2044 | OdePrim parent = (OdePrim)_parent; | ||
2045 | parent.ChildDelink(this); | ||
2046 | } | ||
2047 | } | ||
2048 | else | ||
2049 | { | ||
2050 | disableBody(); | ||
2051 | } | ||
2052 | } | ||
2053 | |||
2054 | if (d.SpaceQuery(m_targetSpace, prim_geom)) | ||
2055 | { | ||
2056 | // _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
2057 | d.SpaceRemove(m_targetSpace, prim_geom); | ||
2058 | } | ||
2059 | |||
2060 | RemoveGeom(); | ||
2061 | |||
2062 | // we don't need to do space calculation because the client sends a position update also. | ||
2063 | |||
2064 | IMesh mesh = null; | ||
2065 | |||
2066 | // Construction of new prim | ||
2067 | if (_parent_scene.needsMeshing(_pbs)) | ||
2068 | { | ||
2069 | float meshlod = _parent_scene.meshSculptLOD; | ||
2070 | |||
2071 | if (IsPhysical) | ||
2072 | meshlod = _parent_scene.MeshSculptphysicalLOD; | ||
2073 | // Don't need to re-enable body.. it's done in SetMesh | ||
2074 | |||
2075 | if (_parent_scene.needsMeshing(_pbs)) | ||
2076 | { | ||
2077 | mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); | ||
2078 | if (mesh == null) | ||
2079 | CheckMeshAsset(); | ||
2080 | else | ||
2081 | m_assetFailed = false; | ||
2082 | } | ||
2083 | |||
2084 | } | ||
2085 | |||
2086 | CreateGeom(m_targetSpace, mesh); | ||
2087 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | ||
2088 | d.Quaternion myrot = new d.Quaternion(); | ||
2089 | myrot.X = _orientation.X; | ||
2090 | myrot.Y = _orientation.Y; | ||
2091 | myrot.Z = _orientation.Z; | ||
2092 | myrot.W = _orientation.W; | ||
2093 | d.GeomSetQuaternion(prim_geom, ref myrot); | ||
2094 | |||
2095 | //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); | ||
2096 | if (IsPhysical && Body == IntPtr.Zero && !childPrim) | ||
2097 | { | ||
2098 | // Re creates body on size. | ||
2099 | // EnableBody also does setMass() | ||
2100 | enableBody(); | ||
2101 | d.BodyEnable(Body); | ||
2102 | } | ||
2103 | |||
2104 | changeSelectedStatus(); | ||
2105 | |||
2106 | if (childPrim) | ||
2107 | { | ||
2108 | if (_parent is OdePrim) | ||
2109 | { | ||
2110 | OdePrim parent = (OdePrim)_parent; | ||
2111 | parent.ChildSetGeom(this); | ||
2112 | } | ||
2113 | } | ||
2114 | resetCollisionAccounting(); | ||
2115 | m_taintsize = _size; | ||
2116 | } | ||
2117 | |||
2118 | /// <summary> | ||
2119 | /// Change prim in response to a float on water taint. | ||
2120 | /// </summary> | ||
2121 | /// <param name="timestep"></param> | ||
2122 | private void changefloatonwater() | ||
2123 | { | ||
2124 | m_collidesWater = m_taintCollidesWater; | ||
2125 | |||
2126 | if (m_collidesWater) | ||
2127 | { | ||
2128 | m_collisionFlags |= CollisionCategories.Water; | ||
2129 | } | ||
2130 | else | ||
2131 | { | ||
2132 | m_collisionFlags &= ~CollisionCategories.Water; | ||
2133 | } | ||
2134 | |||
2135 | if (m_assetFailed) | ||
2136 | d.GeomSetCollideBits(prim_geom, (uint)BadMeshAssetCollideBits); | ||
2137 | else | ||
2138 | |||
2139 | d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); | ||
2140 | } | ||
2141 | /// <summary> | ||
2142 | /// Change prim in response to a shape taint. | ||
2143 | /// </summary> | ||
2144 | private void changeshape() | ||
2145 | { | ||
2146 | m_taintshape = false; | ||
2147 | |||
2148 | // Cleanup of old prim geometry and Bodies | ||
2149 | if (IsPhysical && Body != IntPtr.Zero) | ||
2150 | { | ||
2151 | if (childPrim) | ||
2152 | { | ||
2153 | if (_parent != null) | ||
2154 | { | ||
2155 | OdePrim parent = (OdePrim)_parent; | ||
2156 | parent.ChildDelink(this); | ||
2157 | } | ||
2158 | } | ||
2159 | else | ||
2160 | { | ||
2161 | disableBody(); | ||
2162 | } | ||
2163 | } | ||
2164 | |||
2165 | RemoveGeom(); | ||
2166 | |||
2167 | // we don't need to do space calculation because the client sends a position update also. | ||
2168 | if (_size.X <= 0) _size.X = 0.01f; | ||
2169 | if (_size.Y <= 0) _size.Y = 0.01f; | ||
2170 | if (_size.Z <= 0) _size.Z = 0.01f; | ||
2171 | // Construction of new prim | ||
2172 | |||
2173 | IMesh mesh = null; | ||
2174 | |||
2175 | |||
2176 | if (_parent_scene.needsMeshing(_pbs)) | ||
2177 | { | ||
2178 | // Don't need to re-enable body.. it's done in CreateMesh | ||
2179 | float meshlod = _parent_scene.meshSculptLOD; | ||
2180 | |||
2181 | if (IsPhysical) | ||
2182 | meshlod = _parent_scene.MeshSculptphysicalLOD; | ||
2183 | |||
2184 | // createmesh returns null when it doesn't mesh. | ||
2185 | mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); | ||
2186 | if (mesh == null) | ||
2187 | CheckMeshAsset(); | ||
2188 | else | ||
2189 | m_assetFailed = false; | ||
2190 | } | ||
2191 | |||
2192 | CreateGeom(m_targetSpace, mesh); | ||
2193 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | ||
2194 | d.Quaternion myrot = new d.Quaternion(); | ||
2195 | //myrot.W = _orientation.w; | ||
2196 | myrot.W = _orientation.W; | ||
2197 | myrot.X = _orientation.X; | ||
2198 | myrot.Y = _orientation.Y; | ||
2199 | myrot.Z = _orientation.Z; | ||
2200 | d.GeomSetQuaternion(prim_geom, ref myrot); | ||
2201 | |||
2202 | //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); | ||
2203 | if (IsPhysical && Body == IntPtr.Zero) | ||
2204 | { | ||
2205 | // Re creates body on size. | ||
2206 | // EnableBody also does setMass() | ||
2207 | enableBody(); | ||
2208 | if (Body != IntPtr.Zero) | ||
2209 | { | ||
2210 | d.BodyEnable(Body); | ||
2211 | } | ||
2212 | } | ||
2213 | |||
2214 | changeSelectedStatus(); | ||
2215 | |||
2216 | if (childPrim) | ||
2217 | { | ||
2218 | if (_parent is OdePrim) | ||
2219 | { | ||
2220 | OdePrim parent = (OdePrim)_parent; | ||
2221 | parent.ChildSetGeom(this); | ||
2222 | } | ||
2223 | } | ||
2224 | |||
2225 | resetCollisionAccounting(); | ||
2226 | // m_taintshape = false; | ||
2227 | } | ||
2228 | |||
2229 | /// <summary> | ||
2230 | /// Change prim in response to an add force taint. | ||
2231 | /// </summary> | ||
2232 | private void changeAddForce() | ||
2233 | { | ||
2234 | if (!m_isSelected) | ||
2235 | { | ||
2236 | lock (m_forcelist) | ||
2237 | { | ||
2238 | //m_log.Info("[PHYSICS]: dequeing forcelist"); | ||
2239 | if (IsPhysical) | ||
2240 | { | ||
2241 | Vector3 iforce = Vector3.Zero; | ||
2242 | int i = 0; | ||
2243 | try | ||
2244 | { | ||
2245 | for (i = 0; i < m_forcelist.Count; i++) | ||
2246 | { | ||
2247 | |||
2248 | iforce = iforce + (m_forcelist[i] * 100); | ||
2249 | } | ||
2250 | } | ||
2251 | catch (IndexOutOfRangeException) | ||
2252 | { | ||
2253 | m_forcelist = new List<Vector3>(); | ||
2254 | m_collisionscore = 0; | ||
2255 | m_interpenetrationcount = 0; | ||
2256 | m_taintforce = false; | ||
2257 | return; | ||
2258 | } | ||
2259 | catch (ArgumentOutOfRangeException) | ||
2260 | { | ||
2261 | m_forcelist = new List<Vector3>(); | ||
2262 | m_collisionscore = 0; | ||
2263 | m_interpenetrationcount = 0; | ||
2264 | m_taintforce = false; | ||
2265 | return; | ||
2266 | } | ||
2267 | d.BodyEnable(Body); | ||
2268 | d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z); | ||
2269 | } | ||
2270 | m_forcelist.Clear(); | ||
2271 | } | ||
2272 | |||
2273 | m_collisionscore = 0; | ||
2274 | m_interpenetrationcount = 0; | ||
2275 | } | ||
2276 | |||
2277 | m_taintforce = false; | ||
2278 | } | ||
2279 | |||
2280 | /// <summary> | ||
2281 | /// Change prim in response to a torque taint. | ||
2282 | /// </summary> | ||
2283 | private void changeSetTorque() | ||
2284 | { | ||
2285 | if (!m_isSelected) | ||
2286 | { | ||
2287 | if (IsPhysical && Body != IntPtr.Zero) | ||
2288 | { | ||
2289 | d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z); | ||
2290 | } | ||
2291 | } | ||
2292 | |||
2293 | m_taintTorque = Vector3.Zero; | ||
2294 | } | ||
2295 | |||
2296 | /// <summary> | ||
2297 | /// Change prim in response to an angular force taint. | ||
2298 | /// </summary> | ||
2299 | private void changeAddAngularForce() | ||
2300 | { | ||
2301 | if (!m_isSelected) | ||
2302 | { | ||
2303 | lock (m_angularforcelist) | ||
2304 | { | ||
2305 | //m_log.Info("[PHYSICS]: dequeing forcelist"); | ||
2306 | if (IsPhysical) | ||
2307 | { | ||
2308 | Vector3 iforce = Vector3.Zero; | ||
2309 | for (int i = 0; i < m_angularforcelist.Count; i++) | ||
2310 | { | ||
2311 | iforce = iforce + (m_angularforcelist[i] * 100); | ||
2312 | } | ||
2313 | d.BodyEnable(Body); | ||
2314 | d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z); | ||
2315 | |||
2316 | } | ||
2317 | m_angularforcelist.Clear(); | ||
2318 | } | ||
2319 | |||
2320 | m_collisionscore = 0; | ||
2321 | m_interpenetrationcount = 0; | ||
2322 | } | ||
2323 | |||
2324 | m_taintaddangularforce = false; | ||
2325 | } | ||
2326 | |||
2327 | /// <summary> | ||
2328 | /// Change prim in response to a velocity taint. | ||
2329 | /// </summary> | ||
2330 | private void changevelocity() | ||
2331 | { | ||
2332 | if (!m_isSelected) | ||
2333 | { | ||
2334 | // Not sure exactly why this sleep is here, but from experimentation it appears to stop an avatar | ||
2335 | // walking through a default rez size prim if it keeps kicking it around - justincc. | ||
2336 | Thread.Sleep(20); | ||
2337 | |||
2338 | if (IsPhysical) | ||
2339 | { | ||
2340 | if (Body != IntPtr.Zero) | ||
2341 | { | ||
2342 | d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z); | ||
2343 | } | ||
2344 | } | ||
2345 | |||
2346 | //resetCollisionAccounting(); | ||
2347 | } | ||
2348 | |||
2349 | m_taintVelocity = Vector3.Zero; | ||
2350 | } | ||
2351 | |||
2352 | internal void setPrimForRemoval() | ||
2353 | { | ||
2354 | m_taintremove = true; | ||
2355 | } | ||
2356 | |||
2357 | public override bool Flying | ||
2358 | { | ||
2359 | // no flying prims for you | ||
2360 | get { return false; } | ||
2361 | set { } | ||
2362 | } | ||
2363 | |||
2364 | public override bool IsColliding | ||
2365 | { | ||
2366 | get { return iscolliding; } | ||
2367 | set { iscolliding = value; } | ||
2368 | } | ||
2369 | |||
2370 | public override bool CollidingGround | ||
2371 | { | ||
2372 | get { return false; } | ||
2373 | set { return; } | ||
2374 | } | ||
2375 | |||
2376 | public override bool CollidingObj | ||
2377 | { | ||
2378 | get { return false; } | ||
2379 | set { return; } | ||
2380 | } | ||
2381 | |||
2382 | public override bool ThrottleUpdates | ||
2383 | { | ||
2384 | get { return m_throttleUpdates; } | ||
2385 | set { m_throttleUpdates = value; } | ||
2386 | } | ||
2387 | |||
2388 | public override bool Stopped | ||
2389 | { | ||
2390 | get { return _zeroFlag; } | ||
2391 | } | ||
2392 | |||
2393 | public override Vector3 Position | ||
2394 | { | ||
2395 | get { return _position; } | ||
2396 | |||
2397 | set { _position = value; | ||
2398 | //m_log.Info("[PHYSICS]: " + _position.ToString()); | ||
2399 | } | ||
2400 | } | ||
2401 | |||
2402 | public override Vector3 Size | ||
2403 | { | ||
2404 | get { return _size; } | ||
2405 | set | ||
2406 | { | ||
2407 | if (value.IsFinite()) | ||
2408 | { | ||
2409 | _size = value; | ||
2410 | // m_log.DebugFormat("[PHYSICS]: Set size on {0} to {1}", Name, value); | ||
2411 | } | ||
2412 | else | ||
2413 | { | ||
2414 | m_log.WarnFormat("[PHYSICS]: Got NaN Size on object {0}", Name); | ||
2415 | } | ||
2416 | } | ||
2417 | } | ||
2418 | |||
2419 | public override float Mass | ||
2420 | { | ||
2421 | get { return CalculateMass(); } | ||
2422 | } | ||
2423 | |||
2424 | public override Vector3 Force | ||
2425 | { | ||
2426 | //get { return Vector3.Zero; } | ||
2427 | get { return m_force; } | ||
2428 | set | ||
2429 | { | ||
2430 | if (value.IsFinite()) | ||
2431 | { | ||
2432 | m_force = value; | ||
2433 | } | ||
2434 | else | ||
2435 | { | ||
2436 | m_log.WarnFormat("[PHYSICS]: NaN in Force Applied to an Object {0}", Name); | ||
2437 | } | ||
2438 | } | ||
2439 | } | ||
2440 | |||
2441 | public override int VehicleType | ||
2442 | { | ||
2443 | get { return (int)m_vehicle.Type; } | ||
2444 | set { m_vehicle.ProcessTypeChange((Vehicle)value); } | ||
2445 | } | ||
2446 | |||
2447 | public override void VehicleFloatParam(int param, float value) | ||
2448 | { | ||
2449 | m_vehicle.ProcessFloatVehicleParam((Vehicle) param, value); | ||
2450 | } | ||
2451 | |||
2452 | public override void VehicleVectorParam(int param, Vector3 value) | ||
2453 | { | ||
2454 | m_vehicle.ProcessVectorVehicleParam((Vehicle) param, value); | ||
2455 | } | ||
2456 | |||
2457 | public override void VehicleRotationParam(int param, Quaternion rotation) | ||
2458 | { | ||
2459 | m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation); | ||
2460 | } | ||
2461 | |||
2462 | public override void VehicleFlags(int param, bool remove) | ||
2463 | { | ||
2464 | m_vehicle.ProcessVehicleFlags(param, remove); | ||
2465 | } | ||
2466 | |||
2467 | public override void SetVolumeDetect(int param) | ||
2468 | { | ||
2469 | // We have to lock the scene here so that an entire simulate loop either uses volume detect for all | ||
2470 | // possible collisions with this prim or for none of them. | ||
2471 | lock (_parent_scene.OdeLock) | ||
2472 | { | ||
2473 | m_isVolumeDetect = (param != 0); | ||
2474 | } | ||
2475 | } | ||
2476 | |||
2477 | public override Vector3 CenterOfMass | ||
2478 | { | ||
2479 | get { return Vector3.Zero; } | ||
2480 | } | ||
2481 | |||
2482 | public override Vector3 GeometricCenter | ||
2483 | { | ||
2484 | get { return Vector3.Zero; } | ||
2485 | } | ||
2486 | |||
2487 | public override PrimitiveBaseShape Shape | ||
2488 | { | ||
2489 | set | ||
2490 | { | ||
2491 | _pbs = value; | ||
2492 | m_assetFailed = false; | ||
2493 | m_taintshape = true; | ||
2494 | } | ||
2495 | } | ||
2496 | |||
2497 | public override Vector3 Velocity | ||
2498 | { | ||
2499 | get | ||
2500 | { | ||
2501 | // Average previous velocity with the new one so | ||
2502 | // client object interpolation works a 'little' better | ||
2503 | if (_zeroFlag) | ||
2504 | return Vector3.Zero; | ||
2505 | |||
2506 | Vector3 returnVelocity = Vector3.Zero; | ||
2507 | returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2' | ||
2508 | returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f; | ||
2509 | returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f; | ||
2510 | return returnVelocity; | ||
2511 | } | ||
2512 | set | ||
2513 | { | ||
2514 | if (value.IsFinite()) | ||
2515 | { | ||
2516 | _velocity = value; | ||
2517 | |||
2518 | m_taintVelocity = value; | ||
2519 | _parent_scene.AddPhysicsActorTaint(this); | ||
2520 | } | ||
2521 | else | ||
2522 | { | ||
2523 | m_log.WarnFormat("[PHYSICS]: Got NaN Velocity in Object {0}", Name); | ||
2524 | } | ||
2525 | |||
2526 | } | ||
2527 | } | ||
2528 | |||
2529 | public override Vector3 Torque | ||
2530 | { | ||
2531 | get | ||
2532 | { | ||
2533 | if (!IsPhysical || Body == IntPtr.Zero) | ||
2534 | return Vector3.Zero; | ||
2535 | |||
2536 | return _torque; | ||
2537 | } | ||
2538 | |||
2539 | set | ||
2540 | { | ||
2541 | if (value.IsFinite()) | ||
2542 | { | ||
2543 | m_taintTorque = value; | ||
2544 | _parent_scene.AddPhysicsActorTaint(this); | ||
2545 | } | ||
2546 | else | ||
2547 | { | ||
2548 | m_log.WarnFormat("[PHYSICS]: Got NaN Torque in Object {0}", Name); | ||
2549 | } | ||
2550 | } | ||
2551 | } | ||
2552 | |||
2553 | public override float CollisionScore | ||
2554 | { | ||
2555 | get { return m_collisionscore; } | ||
2556 | set { m_collisionscore = value; } | ||
2557 | } | ||
2558 | |||
2559 | public override bool Kinematic | ||
2560 | { | ||
2561 | get { return false; } | ||
2562 | set { } | ||
2563 | } | ||
2564 | |||
2565 | public override Quaternion Orientation | ||
2566 | { | ||
2567 | get { return _orientation; } | ||
2568 | set | ||
2569 | { | ||
2570 | if (QuaternionIsFinite(value)) | ||
2571 | _orientation = value; | ||
2572 | else | ||
2573 | m_log.WarnFormat("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object {0}", Name); | ||
2574 | } | ||
2575 | } | ||
2576 | |||
2577 | private static bool QuaternionIsFinite(Quaternion q) | ||
2578 | { | ||
2579 | if (Single.IsNaN(q.X) || Single.IsInfinity(q.X)) | ||
2580 | return false; | ||
2581 | if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y)) | ||
2582 | return false; | ||
2583 | if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z)) | ||
2584 | return false; | ||
2585 | if (Single.IsNaN(q.W) || Single.IsInfinity(q.W)) | ||
2586 | return false; | ||
2587 | return true; | ||
2588 | } | ||
2589 | |||
2590 | public override Vector3 Acceleration | ||
2591 | { | ||
2592 | get { return _acceleration; } | ||
2593 | set { _acceleration = value; } | ||
2594 | } | ||
2595 | |||
2596 | public override void AddForce(Vector3 force, bool pushforce) | ||
2597 | { | ||
2598 | if (force.IsFinite()) | ||
2599 | { | ||
2600 | lock (m_forcelist) | ||
2601 | m_forcelist.Add(force); | ||
2602 | |||
2603 | m_taintforce = true; | ||
2604 | } | ||
2605 | else | ||
2606 | { | ||
2607 | m_log.WarnFormat("[PHYSICS]: Got Invalid linear force vector from Scene in Object {0}", Name); | ||
2608 | } | ||
2609 | //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString()); | ||
2610 | } | ||
2611 | |||
2612 | public override void AddAngularForce(Vector3 force, bool pushforce) | ||
2613 | { | ||
2614 | if (force.IsFinite()) | ||
2615 | { | ||
2616 | m_angularforcelist.Add(force); | ||
2617 | m_taintaddangularforce = true; | ||
2618 | } | ||
2619 | else | ||
2620 | { | ||
2621 | m_log.WarnFormat("[PHYSICS]: Got Invalid Angular force vector from Scene in Object {0}", Name); | ||
2622 | } | ||
2623 | } | ||
2624 | |||
2625 | public override Vector3 RotationalVelocity | ||
2626 | { | ||
2627 | get | ||
2628 | { | ||
2629 | Vector3 pv = Vector3.Zero; | ||
2630 | if (_zeroFlag) | ||
2631 | return pv; | ||
2632 | m_lastUpdateSent = false; | ||
2633 | |||
2634 | if (m_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
2635 | return pv; | ||
2636 | |||
2637 | return m_rotationalVelocity; | ||
2638 | } | ||
2639 | set | ||
2640 | { | ||
2641 | if (value.IsFinite()) | ||
2642 | { | ||
2643 | m_rotationalVelocity = value; | ||
2644 | setAngularVelocity(value.X, value.Y, value.Z); | ||
2645 | } | ||
2646 | else | ||
2647 | { | ||
2648 | m_log.WarnFormat("[PHYSICS]: Got NaN RotationalVelocity in Object {0}", Name); | ||
2649 | } | ||
2650 | } | ||
2651 | } | ||
2652 | |||
2653 | public override void CrossingFailure() | ||
2654 | { | ||
2655 | /* | ||
2656 | m_crossingfailures++; | ||
2657 | if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds) | ||
2658 | { | ||
2659 | base.RaiseOutOfBounds(_position); | ||
2660 | return; | ||
2661 | } | ||
2662 | else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds) | ||
2663 | { | ||
2664 | m_log.Warn("[PHYSICS]: Too many crossing failures for: " + Name); | ||
2665 | } | ||
2666 | */ | ||
2667 | |||
2668 | d.AllocateODEDataForThread(0U); | ||
2669 | |||
2670 | _position.X = Util.Clip(_position.X, 0.5f, _parent_scene.WorldExtents.X - 0.5f); | ||
2671 | _position.Y = Util.Clip(_position.Y, 0.5f, _parent_scene.WorldExtents.Y - 0.5f); | ||
2672 | _position.Z = Util.Clip(_position.Z + 0.2f, -100f, 50000f); | ||
2673 | |||
2674 | m_lastposition = _position; | ||
2675 | _velocity.X = 0; | ||
2676 | _velocity.Y = 0; | ||
2677 | _velocity.Z = 0; | ||
2678 | |||
2679 | m_lastVelocity = _velocity; | ||
2680 | |||
2681 | if (Body != IntPtr.Zero) | ||
2682 | { | ||
2683 | d.BodySetLinearVel(Body, 0, 0, 0); // stop it | ||
2684 | d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); | ||
2685 | } | ||
2686 | |||
2687 | if(m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) | ||
2688 | m_vehicle.Stop(); // this also updates vehicle last position from the body position | ||
2689 | |||
2690 | enableBodySoft(); | ||
2691 | |||
2692 | outofBounds = false; | ||
2693 | base.RequestPhysicsterseUpdate(); | ||
2694 | |||
2695 | } | ||
2696 | |||
2697 | public override float Buoyancy | ||
2698 | { | ||
2699 | get { return m_buoyancy; } | ||
2700 | set { m_buoyancy = value; } | ||
2701 | } | ||
2702 | |||
2703 | public override void link(PhysicsActor obj) | ||
2704 | { | ||
2705 | m_taintparent = obj; | ||
2706 | } | ||
2707 | |||
2708 | public override void delink() | ||
2709 | { | ||
2710 | m_taintparent = null; | ||
2711 | } | ||
2712 | |||
2713 | public override void LockAngularMotion(byte axislocks) | ||
2714 | { | ||
2715 | // m_log.DebugFormat("[axislocks]: {0}", axislocks); | ||
2716 | m_taintAngularLock = axislocks; | ||
2717 | } | ||
2718 | |||
2719 | internal void UpdatePositionAndVelocity() | ||
2720 | { | ||
2721 | // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! | ||
2722 | if (outofBounds) | ||
2723 | return; | ||
2724 | if (_parent == null) | ||
2725 | { | ||
2726 | Vector3 pv = Vector3.Zero; | ||
2727 | bool lastZeroFlag = _zeroFlag; | ||
2728 | float m_minvelocity = 0; | ||
2729 | if (Body != IntPtr.Zero) // FIXME -> or if it is a joint | ||
2730 | { | ||
2731 | d.Vector3 vec = d.BodyGetPosition(Body); | ||
2732 | d.Quaternion ori = d.BodyGetQuaternion(Body); | ||
2733 | d.Vector3 vel = d.BodyGetLinearVel(Body); | ||
2734 | d.Vector3 rotvel = d.BodyGetAngularVel(Body); | ||
2735 | d.Vector3 torque = d.BodyGetTorque(Body); | ||
2736 | _torque = new Vector3(torque.X, torque.Y, torque.Z); | ||
2737 | Vector3 l_position = Vector3.Zero; | ||
2738 | Quaternion l_orientation = Quaternion.Identity; | ||
2739 | |||
2740 | m_lastposition = _position; | ||
2741 | m_lastorientation = _orientation; | ||
2742 | |||
2743 | l_position.X = vec.X; | ||
2744 | l_position.Y = vec.Y; | ||
2745 | l_position.Z = vec.Z; | ||
2746 | l_orientation.X = ori.X; | ||
2747 | l_orientation.Y = ori.Y; | ||
2748 | l_orientation.Z = ori.Z; | ||
2749 | l_orientation.W = ori.W; | ||
2750 | |||
2751 | if (l_position.Z < 0) | ||
2752 | { | ||
2753 | // This is so prim that get lost underground don't fall forever and suck up | ||
2754 | // | ||
2755 | // Sim resources and memory. | ||
2756 | // Disables the prim's movement physics.... | ||
2757 | // It's a hack and will generate a console message if it fails. | ||
2758 | |||
2759 | //IsPhysical = false; | ||
2760 | |||
2761 | _acceleration.X = 0; | ||
2762 | _acceleration.Y = 0; | ||
2763 | _acceleration.Z = 0; | ||
2764 | |||
2765 | _velocity.X = 0; | ||
2766 | _velocity.Y = 0; | ||
2767 | _velocity.Z = 0; | ||
2768 | m_rotationalVelocity.X = 0; | ||
2769 | m_rotationalVelocity.Y = 0; | ||
2770 | m_rotationalVelocity.Z = 0; | ||
2771 | |||
2772 | if (_parent == null) | ||
2773 | base.RaiseOutOfBounds(_position); | ||
2774 | |||
2775 | if (_parent == null) | ||
2776 | base.RequestPhysicsterseUpdate(); | ||
2777 | |||
2778 | m_throttleUpdates = false; | ||
2779 | throttleCounter = 0; | ||
2780 | _zeroFlag = true; | ||
2781 | //outofBounds = true; | ||
2782 | return; | ||
2783 | } | ||
2784 | |||
2785 | if (l_position.X > ((int)_parent_scene.WorldExtents.X - 0.05f) || l_position.X < 0f || l_position.Y > ((int)_parent_scene.WorldExtents.Y - 0.05f) || l_position.Y < 0f) | ||
2786 | { | ||
2787 | //base.RaiseOutOfBounds(l_position); | ||
2788 | /* | ||
2789 | if (m_crossingfailures < _parent_scene.geomCrossingFailuresBeforeOutofbounds) | ||
2790 | { | ||
2791 | _position = l_position; | ||
2792 | //_parent_scene.remActivePrim(this); | ||
2793 | if (_parent == null) | ||
2794 | base.RequestPhysicsterseUpdate(); | ||
2795 | return; | ||
2796 | } | ||
2797 | else | ||
2798 | { | ||
2799 | if (_parent == null) | ||
2800 | base.RaiseOutOfBounds(l_position); | ||
2801 | return; | ||
2802 | } | ||
2803 | */ | ||
2804 | outofBounds = true; | ||
2805 | // part near the border on outside | ||
2806 | if (l_position.X < 0) | ||
2807 | Util.Clamp(l_position.X, -0.1f, -2f); | ||
2808 | else | ||
2809 | Util.Clamp(l_position.X, _parent_scene.WorldExtents.X + 0.1f, _parent_scene.WorldExtents.X + 2f); | ||
2810 | if (l_position.Y < 0) | ||
2811 | Util.Clamp(l_position.Y, -0.1f, -2f); | ||
2812 | else | ||
2813 | Util.Clamp(l_position.Y, _parent_scene.WorldExtents.Y + 0.1f, _parent_scene.WorldExtents.Y + 2f); | ||
2814 | |||
2815 | d.BodySetPosition(Body, l_position.X, l_position.Y, l_position.Z); | ||
2816 | |||
2817 | // stop it | ||
2818 | d.BodySetAngularVel(Body, 0, 0, 0); | ||
2819 | d.BodySetLinearVel(Body, 0, 0, 0); | ||
2820 | disableBodySoft(); | ||
2821 | |||
2822 | _position = l_position; | ||
2823 | // tell framework to fix it | ||
2824 | if (_parent == null) | ||
2825 | base.RequestPhysicsterseUpdate(); | ||
2826 | return; | ||
2827 | } | ||
2828 | |||
2829 | |||
2830 | //float Adiff = 1.0f - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)); | ||
2831 | //Console.WriteLine("Adiff " + Name + " = " + Adiff); | ||
2832 | if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02) | ||
2833 | && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02) | ||
2834 | && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02) | ||
2835 | // && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.01)) | ||
2836 | && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.0001)) // KF 0.01 is far to large | ||
2837 | { | ||
2838 | _zeroFlag = true; | ||
2839 | //Console.WriteLine("ZFT 2"); | ||
2840 | m_throttleUpdates = false; | ||
2841 | } | ||
2842 | else | ||
2843 | { | ||
2844 | //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString()); | ||
2845 | _zeroFlag = false; | ||
2846 | m_lastUpdateSent = false; | ||
2847 | //m_throttleUpdates = false; | ||
2848 | } | ||
2849 | |||
2850 | if (_zeroFlag) | ||
2851 | { | ||
2852 | _velocity.X = 0.0f; | ||
2853 | _velocity.Y = 0.0f; | ||
2854 | _velocity.Z = 0.0f; | ||
2855 | |||
2856 | _acceleration.X = 0; | ||
2857 | _acceleration.Y = 0; | ||
2858 | _acceleration.Z = 0; | ||
2859 | |||
2860 | //_orientation.w = 0f; | ||
2861 | //_orientation.X = 0f; | ||
2862 | //_orientation.Y = 0f; | ||
2863 | //_orientation.Z = 0f; | ||
2864 | m_rotationalVelocity.X = 0; | ||
2865 | m_rotationalVelocity.Y = 0; | ||
2866 | m_rotationalVelocity.Z = 0; | ||
2867 | if (!m_lastUpdateSent) | ||
2868 | { | ||
2869 | m_throttleUpdates = false; | ||
2870 | throttleCounter = 0; | ||
2871 | m_rotationalVelocity = pv; | ||
2872 | |||
2873 | if (_parent == null) | ||
2874 | { | ||
2875 | base.RequestPhysicsterseUpdate(); | ||
2876 | } | ||
2877 | |||
2878 | m_lastUpdateSent = true; | ||
2879 | } | ||
2880 | } | ||
2881 | else | ||
2882 | { | ||
2883 | if (lastZeroFlag != _zeroFlag) | ||
2884 | { | ||
2885 | if (_parent == null) | ||
2886 | { | ||
2887 | base.RequestPhysicsterseUpdate(); | ||
2888 | } | ||
2889 | } | ||
2890 | |||
2891 | m_lastVelocity = _velocity; | ||
2892 | |||
2893 | _position = l_position; | ||
2894 | |||
2895 | _velocity.X = vel.X; | ||
2896 | _velocity.Y = vel.Y; | ||
2897 | _velocity.Z = vel.Z; | ||
2898 | |||
2899 | _acceleration = ((_velocity - m_lastVelocity) / 0.1f); | ||
2900 | _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f); | ||
2901 | //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString()); | ||
2902 | |||
2903 | // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing... | ||
2904 | // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large. | ||
2905 | // reducing this to 0.02m/frame seems to help the angular rubberbanding quite a bit, however, to make sure it doesn't affect elevators and vehicles | ||
2906 | // adding these logical exclusion situations to maintain this where I think it was intended to be. | ||
2907 | if (m_throttleUpdates || PIDActive || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero)) | ||
2908 | { | ||
2909 | m_minvelocity = 0.5f; | ||
2910 | } | ||
2911 | else | ||
2912 | { | ||
2913 | m_minvelocity = 0.02f; | ||
2914 | } | ||
2915 | |||
2916 | if (_velocity.ApproxEquals(pv, m_minvelocity)) | ||
2917 | { | ||
2918 | m_rotationalVelocity = pv; | ||
2919 | } | ||
2920 | else | ||
2921 | { | ||
2922 | m_rotationalVelocity = new Vector3(rotvel.X, rotvel.Y, rotvel.Z); | ||
2923 | } | ||
2924 | |||
2925 | //m_log.Debug("ODE: " + m_rotationalVelocity.ToString()); | ||
2926 | _orientation.X = ori.X; | ||
2927 | _orientation.Y = ori.Y; | ||
2928 | _orientation.Z = ori.Z; | ||
2929 | _orientation.W = ori.W; | ||
2930 | m_lastUpdateSent = false; | ||
2931 | if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate) | ||
2932 | { | ||
2933 | if (_parent == null) | ||
2934 | { | ||
2935 | base.RequestPhysicsterseUpdate(); | ||
2936 | } | ||
2937 | } | ||
2938 | else | ||
2939 | { | ||
2940 | throttleCounter++; | ||
2941 | } | ||
2942 | } | ||
2943 | m_lastposition = l_position; | ||
2944 | } | ||
2945 | else | ||
2946 | { | ||
2947 | // Not a body.. so Make sure the client isn't interpolating | ||
2948 | _velocity.X = 0; | ||
2949 | _velocity.Y = 0; | ||
2950 | _velocity.Z = 0; | ||
2951 | |||
2952 | _acceleration.X = 0; | ||
2953 | _acceleration.Y = 0; | ||
2954 | _acceleration.Z = 0; | ||
2955 | |||
2956 | m_rotationalVelocity.X = 0; | ||
2957 | m_rotationalVelocity.Y = 0; | ||
2958 | m_rotationalVelocity.Z = 0; | ||
2959 | _zeroFlag = true; | ||
2960 | } | ||
2961 | } | ||
2962 | } | ||
2963 | |||
2964 | public override bool FloatOnWater | ||
2965 | { | ||
2966 | set { | ||
2967 | m_taintCollidesWater = value; | ||
2968 | _parent_scene.AddPhysicsActorTaint(this); | ||
2969 | } | ||
2970 | } | ||
2971 | |||
2972 | public override void SetMomentum(Vector3 momentum) | ||
2973 | { | ||
2974 | } | ||
2975 | |||
2976 | public override Vector3 PIDTarget | ||
2977 | { | ||
2978 | set | ||
2979 | { | ||
2980 | if (value.IsFinite()) | ||
2981 | { | ||
2982 | m_PIDTarget = value; | ||
2983 | } | ||
2984 | else | ||
2985 | m_log.WarnFormat("[PHYSICS]: Got NaN PIDTarget from Scene on Object {0}", Name); | ||
2986 | } | ||
2987 | } | ||
2988 | |||
2989 | public override bool PIDActive { get; set; } | ||
2990 | public override float PIDTau { set { m_PIDTau = value; } } | ||
2991 | |||
2992 | public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } | ||
2993 | public override bool PIDHoverActive { get { return m_useHoverPID;} set { m_useHoverPID = value; } } | ||
2994 | public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } | ||
2995 | public override float PIDHoverTau { set { m_PIDHoverTau = value; } } | ||
2996 | |||
2997 | public override Quaternion APIDTarget{ set { return; } } | ||
2998 | |||
2999 | public override bool APIDActive{ set { return; } } | ||
3000 | |||
3001 | public override float APIDStrength{ set { return; } } | ||
3002 | |||
3003 | public override float APIDDamping{ set { return; } } | ||
3004 | |||
3005 | private void createAMotor(byte axislock) | ||
3006 | { | ||
3007 | if (Body == IntPtr.Zero) | ||
3008 | return; | ||
3009 | |||
3010 | if (Amotor != IntPtr.Zero) | ||
3011 | { | ||
3012 | d.JointDestroy(Amotor); | ||
3013 | Amotor = IntPtr.Zero; | ||
3014 | } | ||
3015 | |||
3016 | if(axislock == 0) | ||
3017 | return; | ||
3018 | |||
3019 | int axisnum = 0; | ||
3020 | bool axisX = false; | ||
3021 | bool axisY = false; | ||
3022 | bool axisZ = false; | ||
3023 | if((axislock & 0x02) != 0) | ||
3024 | { | ||
3025 | axisnum++; | ||
3026 | axisX = true; | ||
3027 | } | ||
3028 | if((axislock & 0x04) != 0) | ||
3029 | { | ||
3030 | axisnum++; | ||
3031 | axisY = true; | ||
3032 | } | ||
3033 | if((axislock & 0x08) != 0) | ||
3034 | { | ||
3035 | axisnum++; | ||
3036 | axisZ = true; | ||
3037 | } | ||
3038 | |||
3039 | if(axisnum == 0) | ||
3040 | return; | ||
3041 | // stop it | ||
3042 | d.BodySetTorque(Body, 0, 0, 0); | ||
3043 | d.BodySetAngularVel(Body, 0, 0, 0); | ||
3044 | |||
3045 | Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); | ||
3046 | d.JointAttach(Amotor, Body, IntPtr.Zero); | ||
3047 | |||
3048 | d.JointSetAMotorMode(Amotor, 0); | ||
3049 | |||
3050 | d.JointSetAMotorNumAxes(Amotor, axisnum); | ||
3051 | |||
3052 | // get current orientation to lock | ||
3053 | |||
3054 | d.Quaternion dcur = d.BodyGetQuaternion(Body); | ||
3055 | Quaternion curr; // crap convertion between identical things | ||
3056 | curr.X = dcur.X; | ||
3057 | curr.Y = dcur.Y; | ||
3058 | curr.Z = dcur.Z; | ||
3059 | curr.W = dcur.W; | ||
3060 | Vector3 ax; | ||
3061 | |||
3062 | int i = 0; | ||
3063 | int j = 0; | ||
3064 | if (axisX) | ||
3065 | { | ||
3066 | ax = (new Vector3(1, 0, 0)) * curr; // rotate world X to current local X | ||
3067 | d.JointSetAMotorAxis(Amotor, 0, 0, ax.X, ax.Y, ax.Z); | ||
3068 | d.JointSetAMotorAngle(Amotor, 0, 0); | ||
3069 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.LoStop, 0f); | ||
3070 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.HiStop, 0f); | ||
3071 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.Vel, 0); | ||
3072 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.FudgeFactor, 0.0001f); | ||
3073 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.Bounce, 0f); | ||
3074 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.CFM, 0f); | ||
3075 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.FMax, 5e8f); | ||
3076 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.StopCFM, 0f); | ||
3077 | d.JointSetAMotorParam(Amotor, (int)d.JointParam.StopERP, 0.8f); | ||
3078 | i++; | ||
3079 | j = 256; // move to next axis set | ||
3080 | } | ||
3081 | |||
3082 | if (axisY) | ||
3083 | { | ||
3084 | ax = (new Vector3(0, 1, 0)) * curr; | ||
3085 | d.JointSetAMotorAxis(Amotor, i, 0, ax.X, ax.Y, ax.Z); | ||
3086 | d.JointSetAMotorAngle(Amotor, i, 0); | ||
3087 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.LoStop, 0f); | ||
3088 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.HiStop, 0f); | ||
3089 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.Vel, 0); | ||
3090 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.FudgeFactor, 0.0001f); | ||
3091 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.Bounce, 0f); | ||
3092 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.CFM, 0f); | ||
3093 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.FMax, 5e8f); | ||
3094 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.StopCFM, 0f); | ||
3095 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.StopERP, 0.8f); | ||
3096 | i++; | ||
3097 | j += 256; | ||
3098 | } | ||
3099 | |||
3100 | if (axisZ) | ||
3101 | { | ||
3102 | ax = (new Vector3(0, 0, 1)) * curr; | ||
3103 | d.JointSetAMotorAxis(Amotor, i, 0, ax.X, ax.Y, ax.Z); | ||
3104 | d.JointSetAMotorAngle(Amotor, i, 0); | ||
3105 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.LoStop, 0f); | ||
3106 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.HiStop, 0f); | ||
3107 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.Vel, 0); | ||
3108 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.FudgeFactor, 0.0001f); | ||
3109 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.Bounce, 0f); | ||
3110 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.CFM, 0f); | ||
3111 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.FMax, 5e8f); | ||
3112 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.StopCFM, 0f); | ||
3113 | d.JointSetAMotorParam(Amotor, j + (int)d.JointParam.StopERP, 0.8f); | ||
3114 | } | ||
3115 | } | ||
3116 | |||
3117 | public override void SubscribeEvents(int ms) | ||
3118 | { | ||
3119 | m_eventsubscription = ms; | ||
3120 | _parent_scene.AddCollisionEventReporting(this); | ||
3121 | } | ||
3122 | |||
3123 | public override void UnSubscribeEvents() | ||
3124 | { | ||
3125 | _parent_scene.RemoveCollisionEventReporting(this); | ||
3126 | m_eventsubscription = 0; | ||
3127 | } | ||
3128 | |||
3129 | public override void AddCollisionEvent(uint CollidedWith, ContactPoint contact) | ||
3130 | { | ||
3131 | CollisionEventsThisFrame.AddCollider(CollidedWith, contact); | ||
3132 | } | ||
3133 | |||
3134 | public void SendCollisions() | ||
3135 | { | ||
3136 | if (m_collisionsOnPreviousFrame || CollisionEventsThisFrame.Count > 0) | ||
3137 | { | ||
3138 | base.SendCollisionUpdate(CollisionEventsThisFrame); | ||
3139 | |||
3140 | if (CollisionEventsThisFrame.Count > 0) | ||
3141 | { | ||
3142 | m_collisionsOnPreviousFrame = true; | ||
3143 | CollisionEventsThisFrame.Clear(); | ||
3144 | } | ||
3145 | else | ||
3146 | { | ||
3147 | m_collisionsOnPreviousFrame = false; | ||
3148 | } | ||
3149 | } | ||
3150 | } | ||
3151 | |||
3152 | public override bool SubscribedEvents() | ||
3153 | { | ||
3154 | if (m_eventsubscription > 0) | ||
3155 | return true; | ||
3156 | return false; | ||
3157 | } | ||
3158 | |||
3159 | public override void SetMaterial(int pMaterial) | ||
3160 | { | ||
3161 | m_material = pMaterial; | ||
3162 | } | ||
3163 | |||
3164 | private void CheckMeshAsset() | ||
3165 | { | ||
3166 | if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero) | ||
3167 | { | ||
3168 | m_assetFailed = true; | ||
3169 | Util.FireAndForget(delegate | ||
3170 | { | ||
3171 | RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod; | ||
3172 | if (assetProvider != null) | ||
3173 | assetProvider(_pbs.SculptTexture, MeshAssetReceived); | ||
3174 | }, null, "ODEPrim.CheckMeshAsset"); | ||
3175 | } | ||
3176 | } | ||
3177 | |||
3178 | private void MeshAssetReceived(AssetBase asset) | ||
3179 | { | ||
3180 | if (asset != null && asset.Data != null && asset.Data.Length > 0) | ||
3181 | { | ||
3182 | if (!_pbs.SculptEntry) | ||
3183 | return; | ||
3184 | if (_pbs.SculptTexture.ToString() != asset.ID) | ||
3185 | return; | ||
3186 | |||
3187 | _pbs.SculptData = new byte[asset.Data.Length]; | ||
3188 | asset.Data.CopyTo(_pbs.SculptData, 0); | ||
3189 | // m_assetFailed = false; | ||
3190 | |||
3191 | // m_log.DebugFormat( | ||
3192 | // "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", | ||
3193 | // _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name); | ||
3194 | |||
3195 | m_taintshape = true; | ||
3196 | _parent_scene.AddPhysicsActorTaint(this); | ||
3197 | } | ||
3198 | else | ||
3199 | { | ||
3200 | m_log.WarnFormat( | ||
3201 | "[ODE PRIM]: Could not get mesh/sculpt asset {0} for {1} at {2} in {3}", | ||
3202 | _pbs.SculptTexture, Name, _position, _parent_scene.PhysicsSceneName); | ||
3203 | } | ||
3204 | } | ||
3205 | } | ||
3206 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs b/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs new file mode 100644 index 0000000..78dd7de --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs | |||
@@ -0,0 +1,384 @@ | |||
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 OpenMetaverse; | ||
34 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
35 | using log4net; | ||
36 | |||
37 | namespace OpenSim.Region.PhysicsModule.ODE | ||
38 | { | ||
39 | /// <summary> | ||
40 | /// Processes raycast requests as ODE is in a state to be able to do them. | ||
41 | /// This ensures that it's thread safe and there will be no conflicts. | ||
42 | /// Requests get returned by a different thread then they were requested by. | ||
43 | /// </summary> | ||
44 | public class ODERayCastRequestManager | ||
45 | { | ||
46 | /// <summary> | ||
47 | /// Pending raycast requests | ||
48 | /// </summary> | ||
49 | protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>(); | ||
50 | |||
51 | /// <summary> | ||
52 | /// Pending ray requests | ||
53 | /// </summary> | ||
54 | protected List<ODERayRequest> m_PendingRayRequests = new List<ODERayRequest>(); | ||
55 | |||
56 | /// <summary> | ||
57 | /// Scene that created this object. | ||
58 | /// </summary> | ||
59 | private OdeScene m_scene; | ||
60 | |||
61 | /// <summary> | ||
62 | /// ODE contact array to be filled by the collision testing | ||
63 | /// </summary> | ||
64 | d.ContactGeom[] contacts = new d.ContactGeom[5]; | ||
65 | |||
66 | /// <summary> | ||
67 | /// ODE near callback delegate | ||
68 | /// </summary> | ||
69 | private d.NearCallback nearCallback; | ||
70 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
71 | private List<ContactResult> m_contactResults = new List<ContactResult>(); | ||
72 | |||
73 | |||
74 | public ODERayCastRequestManager(OdeScene pScene) | ||
75 | { | ||
76 | m_scene = pScene; | ||
77 | nearCallback = near; | ||
78 | |||
79 | } | ||
80 | |||
81 | /// <summary> | ||
82 | /// Queues a raycast | ||
83 | /// </summary> | ||
84 | /// <param name="position">Origin of Ray</param> | ||
85 | /// <param name="direction">Ray normal</param> | ||
86 | /// <param name="length">Ray length</param> | ||
87 | /// <param name="retMethod">Return method to send the results</param> | ||
88 | public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) | ||
89 | { | ||
90 | lock (m_PendingRequests) | ||
91 | { | ||
92 | ODERayCastRequest req = new ODERayCastRequest(); | ||
93 | req.callbackMethod = retMethod; | ||
94 | req.length = length; | ||
95 | req.Normal = direction; | ||
96 | req.Origin = position; | ||
97 | |||
98 | m_PendingRequests.Add(req); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | /// <summary> | ||
103 | /// Queues a raycast | ||
104 | /// </summary> | ||
105 | /// <param name="position">Origin of Ray</param> | ||
106 | /// <param name="direction">Ray normal</param> | ||
107 | /// <param name="length">Ray length</param> | ||
108 | /// <param name="count"></param> | ||
109 | /// <param name="retMethod">Return method to send the results</param> | ||
110 | public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod) | ||
111 | { | ||
112 | lock (m_PendingRequests) | ||
113 | { | ||
114 | ODERayRequest req = new ODERayRequest(); | ||
115 | req.callbackMethod = retMethod; | ||
116 | req.length = length; | ||
117 | req.Normal = direction; | ||
118 | req.Origin = position; | ||
119 | req.Count = count; | ||
120 | |||
121 | m_PendingRayRequests.Add(req); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | /// <summary> | ||
126 | /// Process all queued raycast requests | ||
127 | /// </summary> | ||
128 | /// <returns>Time in MS the raycasts took to process.</returns> | ||
129 | public int ProcessQueuedRequests() | ||
130 | { | ||
131 | int time = System.Environment.TickCount; | ||
132 | lock (m_PendingRequests) | ||
133 | { | ||
134 | if (m_PendingRequests.Count > 0) | ||
135 | { | ||
136 | ODERayCastRequest[] reqs = m_PendingRequests.ToArray(); | ||
137 | for (int i = 0; i < reqs.Length; i++) | ||
138 | { | ||
139 | if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast | ||
140 | RayCast(reqs[i]); // if there isn't anyone to send results | ||
141 | } | ||
142 | |||
143 | m_PendingRequests.Clear(); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | lock (m_PendingRayRequests) | ||
148 | { | ||
149 | if (m_PendingRayRequests.Count > 0) | ||
150 | { | ||
151 | ODERayRequest[] reqs = m_PendingRayRequests.ToArray(); | ||
152 | for (int i = 0; i < reqs.Length; i++) | ||
153 | { | ||
154 | if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast | ||
155 | RayCast(reqs[i]); // if there isn't anyone to send results | ||
156 | } | ||
157 | |||
158 | m_PendingRayRequests.Clear(); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | lock (m_contactResults) | ||
163 | m_contactResults.Clear(); | ||
164 | |||
165 | return System.Environment.TickCount - time; | ||
166 | } | ||
167 | |||
168 | /// <summary> | ||
169 | /// Method that actually initiates the raycast | ||
170 | /// </summary> | ||
171 | /// <param name="req"></param> | ||
172 | private void RayCast(ODERayCastRequest req) | ||
173 | { | ||
174 | // NOTE: limit ray length or collisions will take all avaiable stack space | ||
175 | // this value may still be too large, depending on machine configuration | ||
176 | // of maximum stack | ||
177 | float len = req.length; | ||
178 | if (len > 100f) | ||
179 | len = 100f; | ||
180 | |||
181 | // Create the ray | ||
182 | IntPtr ray = d.CreateRay(m_scene.space, len); | ||
183 | d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); | ||
184 | |||
185 | // Collide test | ||
186 | d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback); | ||
187 | |||
188 | // Remove Ray | ||
189 | d.GeomDestroy(ray); | ||
190 | |||
191 | // Define default results | ||
192 | bool hitYN = false; | ||
193 | uint hitConsumerID = 0; | ||
194 | float distance = 999999999999f; | ||
195 | Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f); | ||
196 | Vector3 snormal = Vector3.Zero; | ||
197 | |||
198 | // Find closest contact and object. | ||
199 | lock (m_contactResults) | ||
200 | { | ||
201 | foreach (ContactResult cResult in m_contactResults) | ||
202 | { | ||
203 | if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact)) | ||
204 | { | ||
205 | closestcontact = cResult.Pos; | ||
206 | hitConsumerID = cResult.ConsumerID; | ||
207 | distance = cResult.Depth; | ||
208 | hitYN = true; | ||
209 | snormal = cResult.Normal; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | m_contactResults.Clear(); | ||
214 | } | ||
215 | |||
216 | // Return results | ||
217 | if (req.callbackMethod != null) | ||
218 | req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal); | ||
219 | } | ||
220 | |||
221 | /// <summary> | ||
222 | /// Method that actually initiates the raycast | ||
223 | /// </summary> | ||
224 | /// <param name="req"></param> | ||
225 | private void RayCast(ODERayRequest req) | ||
226 | { | ||
227 | // limit ray length or collisions will take all avaiable stack space | ||
228 | float len = req.length; | ||
229 | if (len > 100f) | ||
230 | len = 100f; | ||
231 | |||
232 | // Create the ray | ||
233 | IntPtr ray = d.CreateRay(m_scene.space, len); | ||
234 | d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); | ||
235 | |||
236 | // Collide test | ||
237 | d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback); | ||
238 | |||
239 | // Remove Ray | ||
240 | d.GeomDestroy(ray); | ||
241 | |||
242 | // Find closest contact and object. | ||
243 | lock (m_contactResults) | ||
244 | { | ||
245 | // Return results | ||
246 | if (req.callbackMethod != null) | ||
247 | req.callbackMethod(m_contactResults); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | // This is the standard Near. Uses space AABBs to speed up detection. | ||
252 | private void near(IntPtr space, IntPtr g1, IntPtr g2) | ||
253 | { | ||
254 | |||
255 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
256 | return; | ||
257 | // if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass) | ||
258 | // return; | ||
259 | |||
260 | // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms. | ||
261 | if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) | ||
262 | { | ||
263 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
264 | return; | ||
265 | |||
266 | // Separating static prim geometry spaces. | ||
267 | // We'll be calling near recursivly if one | ||
268 | // of them is a space to find all of the | ||
269 | // contact points in the space | ||
270 | try | ||
271 | { | ||
272 | d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); | ||
273 | } | ||
274 | catch (AccessViolationException) | ||
275 | { | ||
276 | m_log.Warn("[PHYSICS]: Unable to collide test a space"); | ||
277 | return; | ||
278 | } | ||
279 | //Colliding a space or a geom with a space or a geom. so drill down | ||
280 | |||
281 | //Collide all geoms in each space.. | ||
282 | //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); | ||
283 | //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
288 | return; | ||
289 | |||
290 | int count = 0; | ||
291 | try | ||
292 | { | ||
293 | |||
294 | if (g1 == g2) | ||
295 | return; // Can't collide with yourself | ||
296 | |||
297 | lock (contacts) | ||
298 | { | ||
299 | count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.unmanagedSizeOf); | ||
300 | } | ||
301 | } | ||
302 | catch (SEHException) | ||
303 | { | ||
304 | 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."); | ||
305 | } | ||
306 | catch (Exception e) | ||
307 | { | ||
308 | m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message); | ||
309 | return; | ||
310 | } | ||
311 | |||
312 | PhysicsActor p1 = null; | ||
313 | PhysicsActor p2 = null; | ||
314 | |||
315 | if (g1 != IntPtr.Zero) | ||
316 | m_scene.actor_name_map.TryGetValue(g1, out p1); | ||
317 | |||
318 | if (g2 != IntPtr.Zero) | ||
319 | m_scene.actor_name_map.TryGetValue(g1, out p2); | ||
320 | |||
321 | // Loop over contacts, build results. | ||
322 | for (int i = 0; i < count; i++) | ||
323 | { | ||
324 | if (p1 != null) | ||
325 | { | ||
326 | if (p1 is OdePrim) | ||
327 | { | ||
328 | ContactResult collisionresult = new ContactResult(); | ||
329 | |||
330 | collisionresult.ConsumerID = p1.LocalID; | ||
331 | collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z); | ||
332 | collisionresult.Depth = contacts[i].depth; | ||
333 | collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y, | ||
334 | contacts[i].normal.Z); | ||
335 | lock (m_contactResults) | ||
336 | m_contactResults.Add(collisionresult); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | if (p2 != null) | ||
341 | { | ||
342 | if (p2 is OdePrim) | ||
343 | { | ||
344 | ContactResult collisionresult = new ContactResult(); | ||
345 | |||
346 | collisionresult.ConsumerID = p2.LocalID; | ||
347 | collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z); | ||
348 | collisionresult.Depth = contacts[i].depth; | ||
349 | collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y, | ||
350 | contacts[i].normal.Z); | ||
351 | |||
352 | lock (m_contactResults) | ||
353 | m_contactResults.Add(collisionresult); | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | |||
359 | /// <summary> | ||
360 | /// Dereference the creator scene so that it can be garbage collected if needed. | ||
361 | /// </summary> | ||
362 | internal void Dispose() | ||
363 | { | ||
364 | m_scene = null; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | public struct ODERayCastRequest | ||
369 | { | ||
370 | public Vector3 Origin; | ||
371 | public Vector3 Normal; | ||
372 | public float length; | ||
373 | public RaycastCallback callbackMethod; | ||
374 | } | ||
375 | |||
376 | public struct ODERayRequest | ||
377 | { | ||
378 | public Vector3 Origin; | ||
379 | public Vector3 Normal; | ||
380 | public int Count; | ||
381 | public float length; | ||
382 | public RayCallback callbackMethod; | ||
383 | } | ||
384 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs b/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs new file mode 100644 index 0000000..e2578be --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs | |||
@@ -0,0 +1,46 @@ | |||
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 OpenMetaverse; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
32 | |||
33 | namespace OpenSim.Region.PhysicsModule.ODE | ||
34 | { | ||
35 | class OdePhysicsJoint : PhysicsJoint | ||
36 | { | ||
37 | public override bool IsInPhysicsEngine | ||
38 | { | ||
39 | get | ||
40 | { | ||
41 | return (jointID != IntPtr.Zero); | ||
42 | } | ||
43 | } | ||
44 | public IntPtr jointID; | ||
45 | } | ||
46 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs new file mode 100644 index 0000000..d15568e --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs | |||
@@ -0,0 +1,3541 @@ | |||
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 | // changes for varsize regions | ||
29 | // note that raycasts need to have limited range | ||
30 | // (even in normal regions) | ||
31 | // or application thread stack may just blowup | ||
32 | // see RayCast(ODERayCastRequest req) | ||
33 | |||
34 | using System; | ||
35 | using System.Collections.Generic; | ||
36 | using System.Diagnostics; | ||
37 | using System.IO; | ||
38 | using System.Linq; | ||
39 | using System.Reflection; | ||
40 | using System.Runtime.ExceptionServices; | ||
41 | using System.Runtime.InteropServices; | ||
42 | using System.Threading; | ||
43 | using log4net; | ||
44 | using Nini.Config; | ||
45 | using Mono.Addins; | ||
46 | using OpenMetaverse; | ||
47 | using OpenSim.Framework; | ||
48 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
49 | using OpenSim.Region.Framework.Scenes; | ||
50 | using OpenSim.Region.Framework.Interfaces; | ||
51 | |||
52 | namespace OpenSim.Region.PhysicsModule.ODE | ||
53 | { | ||
54 | public enum StatusIndicators : int | ||
55 | { | ||
56 | Generic = 0, | ||
57 | Start = 1, | ||
58 | End = 2 | ||
59 | } | ||
60 | |||
61 | [Flags] | ||
62 | public enum CollisionCategories : int | ||
63 | { | ||
64 | Disabled = 0, | ||
65 | Geom = 0x00000001, | ||
66 | Body = 0x00000002, | ||
67 | Space = 0x00000004, | ||
68 | Character = 0x00000008, | ||
69 | Land = 0x00000010, | ||
70 | Water = 0x00000020, | ||
71 | Wind = 0x00000040, | ||
72 | Sensor = 0x00000080, | ||
73 | Selected = 0x00000100 | ||
74 | } | ||
75 | |||
76 | /// <summary> | ||
77 | /// Material type for a primitive | ||
78 | /// </summary> | ||
79 | public enum Material : int | ||
80 | { | ||
81 | /// <summary></summary> | ||
82 | Stone = 0, | ||
83 | /// <summary></summary> | ||
84 | Metal = 1, | ||
85 | /// <summary></summary> | ||
86 | Glass = 2, | ||
87 | /// <summary></summary> | ||
88 | Wood = 3, | ||
89 | /// <summary></summary> | ||
90 | Flesh = 4, | ||
91 | /// <summary></summary> | ||
92 | Plastic = 5, | ||
93 | /// <summary></summary> | ||
94 | Rubber = 6 | ||
95 | } | ||
96 | |||
97 | public class OdeScene : PhysicsScene | ||
98 | { | ||
99 | private readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString()); | ||
100 | |||
101 | // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>(); | ||
102 | |||
103 | /// <summary> | ||
104 | /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances. | ||
105 | /// </summary> | ||
106 | /// <remarks> | ||
107 | /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a | ||
108 | /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts | ||
109 | /// uses a static cache at the ODE level. | ||
110 | /// | ||
111 | /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar | ||
112 | /// to | ||
113 | /// | ||
114 | /// mono() [0x489171] | ||
115 | /// mono() [0x4d154f] | ||
116 | /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60] | ||
117 | /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a] | ||
118 | /// | ||
119 | /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option | ||
120 | /// causes OpenSimulator to immediately crash with a native stack trace similar to | ||
121 | /// | ||
122 | /// mono() [0x489171] | ||
123 | /// mono() [0x4d154f] | ||
124 | /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60] | ||
125 | /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82] | ||
126 | /// </remarks> | ||
127 | internal static Object UniversalColliderSyncObject = new Object(); | ||
128 | internal static Object SimulationLock = new Object(); | ||
129 | |||
130 | /// <summary> | ||
131 | /// Is stats collecting enabled for this ODE scene? | ||
132 | /// </summary> | ||
133 | public bool CollectStats { get; set; } | ||
134 | |||
135 | /// <summary> | ||
136 | /// Statistics for this scene. | ||
137 | /// </summary> | ||
138 | private Dictionary<string, float> m_stats = new Dictionary<string, float>(); | ||
139 | |||
140 | /// <summary> | ||
141 | /// Stat name for total number of avatars in this ODE scene. | ||
142 | /// </summary> | ||
143 | public const string ODETotalAvatarsStatName = "ODETotalAvatars"; | ||
144 | |||
145 | /// <summary> | ||
146 | /// Stat name for total number of prims in this ODE scene. | ||
147 | /// </summary> | ||
148 | public const string ODETotalPrimsStatName = "ODETotalPrims"; | ||
149 | |||
150 | /// <summary> | ||
151 | /// Stat name for total number of prims with active physics in this ODE scene. | ||
152 | /// </summary> | ||
153 | public const string ODEActivePrimsStatName = "ODEActivePrims"; | ||
154 | |||
155 | /// <summary> | ||
156 | /// Stat name for the total time spent in ODE frame processing. | ||
157 | /// </summary> | ||
158 | /// <remarks> | ||
159 | /// A sanity check for the main scene loop physics time. | ||
160 | /// </remarks> | ||
161 | public const string ODETotalFrameMsStatName = "ODETotalFrameMS"; | ||
162 | |||
163 | /// <summary> | ||
164 | /// Stat name for time spent processing avatar taints per frame | ||
165 | /// </summary> | ||
166 | public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS"; | ||
167 | |||
168 | /// <summary> | ||
169 | /// Stat name for time spent processing prim taints per frame | ||
170 | /// </summary> | ||
171 | public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS"; | ||
172 | |||
173 | /// <summary> | ||
174 | /// Stat name for time spent calculating avatar forces per frame. | ||
175 | /// </summary> | ||
176 | public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS"; | ||
177 | |||
178 | /// <summary> | ||
179 | /// Stat name for time spent calculating prim forces per frame | ||
180 | /// </summary> | ||
181 | public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS"; | ||
182 | |||
183 | /// <summary> | ||
184 | /// Stat name for time spent fulfilling raycasting requests per frame | ||
185 | /// </summary> | ||
186 | public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS"; | ||
187 | |||
188 | /// <summary> | ||
189 | /// Stat name for time spent in native code that actually steps through the simulation. | ||
190 | /// </summary> | ||
191 | public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS"; | ||
192 | |||
193 | /// <summary> | ||
194 | /// Stat name for the number of milliseconds that ODE spends in native space collision code. | ||
195 | /// </summary> | ||
196 | public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS"; | ||
197 | |||
198 | /// <summary> | ||
199 | /// Stat name for milliseconds that ODE spends in native geom collision code. | ||
200 | /// </summary> | ||
201 | public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS"; | ||
202 | |||
203 | /// <summary> | ||
204 | /// Time spent in collision processing that is not spent in native space or geom collision code. | ||
205 | /// </summary> | ||
206 | public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS"; | ||
207 | |||
208 | /// <summary> | ||
209 | /// Stat name for time spent notifying listeners of collisions | ||
210 | /// </summary> | ||
211 | public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS"; | ||
212 | |||
213 | /// <summary> | ||
214 | /// Stat name for milliseconds spent updating avatar position and velocity | ||
215 | /// </summary> | ||
216 | public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS"; | ||
217 | |||
218 | /// <summary> | ||
219 | /// Stat name for the milliseconds spent updating prim position and velocity | ||
220 | /// </summary> | ||
221 | public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS"; | ||
222 | |||
223 | /// <summary> | ||
224 | /// Stat name for avatar collisions with another entity. | ||
225 | /// </summary> | ||
226 | public const string ODEAvatarContactsStatsName = "ODEAvatarContacts"; | ||
227 | |||
228 | /// <summary> | ||
229 | /// Stat name for prim collisions with another entity. | ||
230 | /// </summary> | ||
231 | public const string ODEPrimContactsStatName = "ODEPrimContacts"; | ||
232 | |||
233 | /// <summary> | ||
234 | /// Used to hold tick numbers for stat collection purposes. | ||
235 | /// </summary> | ||
236 | private int m_nativeCollisionStartTick; | ||
237 | |||
238 | /// <summary> | ||
239 | /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback. | ||
240 | /// </summary> | ||
241 | private bool m_inCollisionTiming; | ||
242 | |||
243 | /// <summary> | ||
244 | /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object | ||
245 | /// collisions occured using the _perloopcontact if stats collection is enabled. | ||
246 | /// </summary> | ||
247 | private int m_tempAvatarCollisionsThisFrame; | ||
248 | |||
249 | /// <summary> | ||
250 | /// Used in calculating physics frame time dilation | ||
251 | /// </summary> | ||
252 | private int tickCountFrameRun; | ||
253 | |||
254 | /// <summary> | ||
255 | /// Used in calculating physics frame time dilation | ||
256 | /// </summary> | ||
257 | private int latertickcount; | ||
258 | |||
259 | private Random fluidRandomizer = new Random(Environment.TickCount); | ||
260 | |||
261 | private uint m_regionWidth = Constants.RegionSize; | ||
262 | private uint m_regionHeight = Constants.RegionSize; | ||
263 | |||
264 | private float ODE_STEPSIZE = 0.0178f; | ||
265 | private float metersInSpace = 29.9f; | ||
266 | private float m_timeDilation = 1.0f; | ||
267 | |||
268 | public float gravityx = 0f; | ||
269 | public float gravityy = 0f; | ||
270 | public float gravityz = -9.8f; | ||
271 | |||
272 | public float AvatarTerminalVelocity { get; set; } | ||
273 | |||
274 | private float contactsurfacelayer = 0.001f; | ||
275 | |||
276 | private int HashspaceLow = -5; | ||
277 | private int HashspaceHigh = 12; | ||
278 | |||
279 | private float waterlevel = 0f; | ||
280 | private int framecount = 0; | ||
281 | //private int m_returncollisions = 10; | ||
282 | |||
283 | private IntPtr contactgroup; | ||
284 | |||
285 | // internal IntPtr WaterGeom; | ||
286 | |||
287 | private float nmTerrainContactFriction = 255.0f; | ||
288 | private float nmTerrainContactBounce = 0.1f; | ||
289 | private float nmTerrainContactERP = 0.1025f; | ||
290 | |||
291 | private float mTerrainContactFriction = 75f; | ||
292 | private float mTerrainContactBounce = 0.1f; | ||
293 | private float mTerrainContactERP = 0.05025f; | ||
294 | |||
295 | private float nmAvatarObjectContactFriction = 250f; | ||
296 | private float nmAvatarObjectContactBounce = 0.1f; | ||
297 | |||
298 | private float mAvatarObjectContactFriction = 75f; | ||
299 | private float mAvatarObjectContactBounce = 0.1f; | ||
300 | |||
301 | private float avPIDD = 3200f; | ||
302 | private float avPIDP = 1400f; | ||
303 | private float avCapRadius = 0.37f; | ||
304 | private float avStandupTensor = 2000000f; | ||
305 | |||
306 | /// <summary> | ||
307 | /// true = old compatibility mode with leaning capsule; false = new corrected mode | ||
308 | /// </summary> | ||
309 | /// <remarks> | ||
310 | /// Even when set to false, the capsule still tilts but this is done in a different way. | ||
311 | /// </remarks> | ||
312 | public bool IsAvCapsuleTilted { get; private set; } | ||
313 | |||
314 | private float avDensity = 80f; | ||
315 | private float avMovementDivisorWalk = 1.3f; | ||
316 | private float avMovementDivisorRun = 0.8f; | ||
317 | private float minimumGroundFlightOffset = 3f; | ||
318 | public float maximumMassObject = 10000.01f; | ||
319 | |||
320 | public bool meshSculptedPrim = true; | ||
321 | public bool forceSimplePrimMeshing = false; | ||
322 | |||
323 | public float meshSculptLOD = 32; | ||
324 | public float MeshSculptphysicalLOD = 16; | ||
325 | |||
326 | public float geomDefaultDensity = 10.000006836f; | ||
327 | |||
328 | public int geomContactPointsStartthrottle = 3; | ||
329 | public int geomUpdatesPerThrottledUpdate = 15; | ||
330 | private const int avatarExpectedContacts = 3; | ||
331 | |||
332 | public float bodyPIDD = 35f; | ||
333 | public float bodyPIDG = 25; | ||
334 | |||
335 | public int bodyFramesAutoDisable = 20; | ||
336 | |||
337 | private bool m_filterCollisions = true; | ||
338 | |||
339 | private d.NearCallback nearCallback; | ||
340 | public d.TriCallback triCallback; | ||
341 | public d.TriArrayCallback triArrayCallback; | ||
342 | |||
343 | /// <summary> | ||
344 | /// Avatars in the physics scene. | ||
345 | /// </summary> | ||
346 | private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>(); | ||
347 | |||
348 | /// <summary> | ||
349 | /// Prims in the physics scene. | ||
350 | /// </summary> | ||
351 | private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>(); | ||
352 | |||
353 | /// <summary> | ||
354 | /// Prims in the physics scene that are subject to physics, not just collisions. | ||
355 | /// </summary> | ||
356 | private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>(); | ||
357 | |||
358 | /// <summary> | ||
359 | /// Prims that the simulator has created/deleted/updated and so need updating in ODE. | ||
360 | /// </summary> | ||
361 | private readonly HashSet<OdePrim> _taintedPrims = new HashSet<OdePrim>(); | ||
362 | |||
363 | /// <summary> | ||
364 | /// Record a character that has taints to be processed. | ||
365 | /// </summary> | ||
366 | private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>(); | ||
367 | |||
368 | /// <summary> | ||
369 | /// Keep record of contacts in the physics loop so that we can remove duplicates. | ||
370 | /// </summary> | ||
371 | private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>(); | ||
372 | |||
373 | /// <summary> | ||
374 | /// A dictionary of actors that should receive collision events. | ||
375 | /// </summary> | ||
376 | private readonly Dictionary<uint, PhysicsActor> m_collisionEventActors = new Dictionary<uint, PhysicsActor>(); | ||
377 | |||
378 | /// <summary> | ||
379 | /// A dictionary of collision event changes that are waiting to be processed. | ||
380 | /// </summary> | ||
381 | private readonly Dictionary<uint, PhysicsActor> m_collisionEventActorsChanges = new Dictionary<uint, PhysicsActor>(); | ||
382 | |||
383 | /// <summary> | ||
384 | /// Maps a unique geometry id (a memory location) to a physics actor name. | ||
385 | /// </summary> | ||
386 | /// <remarks> | ||
387 | /// Only actors participating in collisions have geometries. This has to be maintained separately from | ||
388 | /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own | ||
389 | /// apart from the singleton PANull | ||
390 | /// </remarks> | ||
391 | public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>(); | ||
392 | |||
393 | /// <summary> | ||
394 | /// Maps a unique geometry id (a memory location) to a physics actor. | ||
395 | /// </summary> | ||
396 | /// <remarks> | ||
397 | /// Only actors participating in collisions have geometries. | ||
398 | /// </remarks> | ||
399 | public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>(); | ||
400 | |||
401 | /// <summary> | ||
402 | /// Defects list to remove characters that no longer have finite positions due to some other bug. | ||
403 | /// </summary> | ||
404 | /// <remarks> | ||
405 | /// Used repeatedly in Simulate() but initialized once here. | ||
406 | /// </remarks> | ||
407 | private readonly List<OdeCharacter> defects = new List<OdeCharacter>(); | ||
408 | |||
409 | private bool m_NINJA_physics_joints_enabled = false; | ||
410 | //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>(); | ||
411 | private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>(); | ||
412 | private d.ContactGeom[] contacts; | ||
413 | |||
414 | /// <summary> | ||
415 | /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active | ||
416 | /// </summary> | ||
417 | private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); | ||
418 | |||
419 | /// <summary> | ||
420 | /// can lock for longer. accessed only by OdeScene. | ||
421 | /// </summary> | ||
422 | private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); | ||
423 | |||
424 | /// <summary> | ||
425 | /// can lock for longer. accessed only by OdeScene. | ||
426 | /// </summary> | ||
427 | private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); | ||
428 | |||
429 | /// <summary> | ||
430 | /// lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active | ||
431 | /// </summary> | ||
432 | private readonly List<string> requestedJointsToBeDeleted = new List<string>(); | ||
433 | |||
434 | private Object externalJointRequestsLock = new Object(); | ||
435 | private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>(); | ||
436 | private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>(); | ||
437 | private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>(); | ||
438 | private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>(); | ||
439 | |||
440 | private d.Contact contact; | ||
441 | private d.Contact TerrainContact; | ||
442 | private d.Contact AvatarMovementprimContact; | ||
443 | private d.Contact AvatarMovementTerrainContact; | ||
444 | private d.Contact WaterContact; | ||
445 | private d.Contact[,] m_materialContacts; | ||
446 | |||
447 | private int m_physicsiterations = 10; | ||
448 | private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag | ||
449 | private readonly PhysicsActor PANull = new NullPhysicsActor(); | ||
450 | private float step_time = 0.0f; | ||
451 | public IntPtr world; | ||
452 | private uint obj2LocalID = 0; | ||
453 | private OdeCharacter cc1; | ||
454 | private OdePrim cp1; | ||
455 | private OdeCharacter cc2; | ||
456 | private OdePrim cp2; | ||
457 | private int p1ExpectedPoints = 0; | ||
458 | private int p2ExpectedPoints = 0; | ||
459 | |||
460 | public IntPtr space; | ||
461 | |||
462 | // split static geometry collision handling into spaces of 30 meters | ||
463 | public IntPtr[,] staticPrimspace; | ||
464 | |||
465 | /// <summary> | ||
466 | /// Used to lock the entire physics scene. Locked during the main part of Simulate() | ||
467 | /// </summary> | ||
468 | internal Object OdeLock = new Object(); | ||
469 | |||
470 | private bool _worldInitialized = false; | ||
471 | |||
472 | public IMesher mesher; | ||
473 | |||
474 | private IConfigSource m_config; | ||
475 | |||
476 | public bool physics_logging = false; | ||
477 | public int physics_logging_interval = 0; | ||
478 | public bool physics_logging_append_existing_logfile = false; | ||
479 | |||
480 | private bool avplanted = false; | ||
481 | private bool av_av_collisions_off = false; | ||
482 | |||
483 | public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); | ||
484 | public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); | ||
485 | |||
486 | private volatile int m_global_contactcount = 0; | ||
487 | |||
488 | private Vector3 m_worldOffset = Vector3.Zero; | ||
489 | public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); | ||
490 | private PhysicsScene m_parentScene = null; | ||
491 | |||
492 | float spacesPerMeterX; | ||
493 | float spacesPerMeterY; | ||
494 | int spaceGridMaxX; | ||
495 | int spaceGridMaxY; | ||
496 | |||
497 | private ODERayCastRequestManager m_rayCastManager; | ||
498 | |||
499 | public Scene m_frameWorkScene = null; | ||
500 | |||
501 | public OdeScene(Scene pscene, IConfigSource psourceconfig, string pname, string pversion) | ||
502 | { | ||
503 | m_config = psourceconfig; | ||
504 | m_frameWorkScene = pscene; | ||
505 | |||
506 | EngineType = pname; | ||
507 | PhysicsSceneName = EngineType + "/" + pscene.RegionInfo.RegionName; | ||
508 | EngineName = pname + " " + pversion; | ||
509 | |||
510 | pscene.RegisterModuleInterface<PhysicsScene>(this); | ||
511 | Vector3 extent = new Vector3(pscene.RegionInfo.RegionSizeX, pscene.RegionInfo.RegionSizeY, pscene.RegionInfo.RegionSizeZ); | ||
512 | Initialise(extent); | ||
513 | InitialiseFromConfig(m_config); | ||
514 | |||
515 | // This may not be that good since terrain may not be avaiable at this point | ||
516 | base.Initialise(pscene.PhysicsRequestAsset, | ||
517 | (pscene.Heightmap != null ? pscene.Heightmap.GetFloatsSerialised() : new float[(int)(extent.X * extent.Y)]), | ||
518 | (float)pscene.RegionInfo.RegionSettings.WaterHeight); | ||
519 | |||
520 | } | ||
521 | |||
522 | public void RegionLoaded() | ||
523 | { | ||
524 | mesher = m_frameWorkScene.RequestModuleInterface<IMesher>(); | ||
525 | if (mesher == null) | ||
526 | m_log.WarnFormat("[ODE SCENE]: No mesher in {0}. Things will not work well.", PhysicsSceneName); | ||
527 | |||
528 | m_frameWorkScene.PhysicsEnabled = true; | ||
529 | } | ||
530 | |||
531 | /// <summary> | ||
532 | /// Initiailizes the scene | ||
533 | /// Sets many properties that ODE requires to be stable | ||
534 | /// These settings need to be tweaked 'exactly' right or weird stuff happens. | ||
535 | /// </summary> | ||
536 | private void Initialise(Vector3 regionExtent) | ||
537 | { | ||
538 | WorldExtents.X = regionExtent.X; | ||
539 | m_regionWidth = (uint)regionExtent.X; | ||
540 | WorldExtents.Y = regionExtent.Y; | ||
541 | m_regionHeight = (uint)regionExtent.Y; | ||
542 | |||
543 | nearCallback = near; | ||
544 | m_rayCastManager = new ODERayCastRequestManager(this); | ||
545 | |||
546 | // Create the world and the first space | ||
547 | world = d.WorldCreate(); | ||
548 | space = d.HashSpaceCreate(IntPtr.Zero); | ||
549 | |||
550 | contactgroup = d.JointGroupCreate(0); | ||
551 | |||
552 | d.WorldSetAutoDisableFlag(world, false); | ||
553 | } | ||
554 | |||
555 | // Initialize from configs | ||
556 | private void InitialiseFromConfig(IConfigSource config) | ||
557 | { | ||
558 | InitializeExtraStats(); | ||
559 | |||
560 | m_config = config; | ||
561 | // Defaults | ||
562 | |||
563 | avPIDD = 2200.0f; | ||
564 | avPIDP = 900.0f; | ||
565 | avStandupTensor = 550000f; | ||
566 | |||
567 | int contactsPerCollision = 80; | ||
568 | |||
569 | if (m_config != null) | ||
570 | { | ||
571 | IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; | ||
572 | if (physicsconfig != null) | ||
573 | { | ||
574 | CollectStats = physicsconfig.GetBoolean("collect_stats", false); | ||
575 | |||
576 | gravityx = physicsconfig.GetFloat("world_gravityx", 0f); | ||
577 | gravityy = physicsconfig.GetFloat("world_gravityy", 0f); | ||
578 | gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); | ||
579 | |||
580 | float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f); | ||
581 | AvatarTerminalVelocity = Util.Clamp<float>(avatarTerminalVelocity, 0, 255f); | ||
582 | if (AvatarTerminalVelocity != avatarTerminalVelocity) | ||
583 | { | ||
584 | m_log.WarnFormat( | ||
585 | "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}", | ||
586 | avatarTerminalVelocity, AvatarTerminalVelocity); | ||
587 | } | ||
588 | |||
589 | HashspaceLow = physicsconfig.GetInt("world_hashspace_level_low", -5); | ||
590 | HashspaceHigh = physicsconfig.GetInt("world_hashspace_level_high", 12); | ||
591 | |||
592 | metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f); | ||
593 | |||
594 | contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f); | ||
595 | |||
596 | nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f); | ||
597 | nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f); | ||
598 | nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f); | ||
599 | |||
600 | mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f); | ||
601 | mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f); | ||
602 | mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f); | ||
603 | |||
604 | nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f); | ||
605 | nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f); | ||
606 | |||
607 | mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f); | ||
608 | mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f); | ||
609 | |||
610 | ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE); | ||
611 | m_physicsiterations = physicsconfig.GetInt("world_solver_iterations", 10); | ||
612 | |||
613 | avDensity = physicsconfig.GetFloat("av_density", 80f); | ||
614 | // avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f); | ||
615 | avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); | ||
616 | avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); | ||
617 | avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); | ||
618 | avplanted = physicsconfig.GetBoolean("av_planted", false); | ||
619 | av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false); | ||
620 | |||
621 | IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); | ||
622 | |||
623 | contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); | ||
624 | |||
625 | geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5); | ||
626 | geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); | ||
627 | |||
628 | geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f); | ||
629 | bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20); | ||
630 | |||
631 | bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f); | ||
632 | bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f); | ||
633 | |||
634 | forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); | ||
635 | meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true); | ||
636 | meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); | ||
637 | MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); | ||
638 | m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); | ||
639 | |||
640 | avPIDD = physicsconfig.GetFloat("av_pid_derivative", 2200.0f); | ||
641 | avPIDP = physicsconfig.GetFloat("av_pid_proportional", 900.0f); | ||
642 | avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor", 550000f); | ||
643 | |||
644 | physics_logging = physicsconfig.GetBoolean("physics_logging", false); | ||
645 | physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); | ||
646 | physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false); | ||
647 | |||
648 | // m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); | ||
649 | minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); | ||
650 | maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | contacts = new d.ContactGeom[contactsPerCollision]; | ||
655 | |||
656 | spacesPerMeterX = 1.0f / metersInSpace; | ||
657 | spacesPerMeterY = 1.0f / metersInSpace; | ||
658 | |||
659 | spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX); | ||
660 | spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY); | ||
661 | |||
662 | // note: limit number of spaces | ||
663 | if (spaceGridMaxX > 24) | ||
664 | { | ||
665 | spaceGridMaxX = 24; | ||
666 | spacesPerMeterX = spaceGridMaxX / WorldExtents.X; | ||
667 | } | ||
668 | if (spaceGridMaxY > 24) | ||
669 | { | ||
670 | spaceGridMaxY = 24; | ||
671 | spacesPerMeterY = spaceGridMaxY / WorldExtents.Y; | ||
672 | } | ||
673 | |||
674 | staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY]; | ||
675 | |||
676 | // make this index limits | ||
677 | spaceGridMaxX--; | ||
678 | spaceGridMaxY--; | ||
679 | |||
680 | // Centeral contact friction and bounce | ||
681 | // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why | ||
682 | // an avatar falls through in Z but not in X or Y when walking on a prim. | ||
683 | contact.surface.mode |= d.ContactFlags.SoftERP; | ||
684 | contact.surface.mu = nmAvatarObjectContactFriction; | ||
685 | contact.surface.bounce = nmAvatarObjectContactBounce; | ||
686 | contact.surface.soft_cfm = 0.010f; | ||
687 | contact.surface.soft_erp = 0.010f; | ||
688 | |||
689 | // Terrain contact friction and Bounce | ||
690 | // This is the *non* moving version. Use this when an avatar | ||
691 | // isn't moving to keep it in place better | ||
692 | TerrainContact.surface.mode |= d.ContactFlags.SoftERP; | ||
693 | TerrainContact.surface.mu = nmTerrainContactFriction; | ||
694 | TerrainContact.surface.bounce = nmTerrainContactBounce; | ||
695 | TerrainContact.surface.soft_erp = nmTerrainContactERP; | ||
696 | |||
697 | WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM); | ||
698 | WaterContact.surface.mu = 0f; // No friction | ||
699 | WaterContact.surface.bounce = 0.0f; // No bounce | ||
700 | WaterContact.surface.soft_cfm = 0.010f; | ||
701 | WaterContact.surface.soft_erp = 0.010f; | ||
702 | |||
703 | // Prim contact friction and bounce | ||
704 | // THis is the *non* moving version of friction and bounce | ||
705 | // Use this when an avatar comes in contact with a prim | ||
706 | // and is moving | ||
707 | AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction; | ||
708 | AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce; | ||
709 | |||
710 | // Terrain contact friction bounce and various error correcting calculations | ||
711 | // Use this when an avatar is in contact with the terrain and moving. | ||
712 | AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP; | ||
713 | AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction; | ||
714 | AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce; | ||
715 | AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP; | ||
716 | |||
717 | /* | ||
718 | <summary></summary> | ||
719 | Stone = 0, | ||
720 | /// <summary></summary> | ||
721 | Metal = 1, | ||
722 | /// <summary></summary> | ||
723 | Glass = 2, | ||
724 | /// <summary></summary> | ||
725 | Wood = 3, | ||
726 | /// <summary></summary> | ||
727 | Flesh = 4, | ||
728 | /// <summary></summary> | ||
729 | Plastic = 5, | ||
730 | /// <summary></summary> | ||
731 | Rubber = 6 | ||
732 | */ | ||
733 | |||
734 | m_materialContacts = new d.Contact[7,2]; | ||
735 | |||
736 | m_materialContacts[(int)Material.Stone, 0] = new d.Contact(); | ||
737 | m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
738 | m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction; | ||
739 | m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
740 | m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f; | ||
741 | m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f; | ||
742 | |||
743 | m_materialContacts[(int)Material.Stone, 1] = new d.Contact(); | ||
744 | m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
745 | m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction; | ||
746 | m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce; | ||
747 | m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f; | ||
748 | m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f; | ||
749 | |||
750 | m_materialContacts[(int)Material.Metal, 0] = new d.Contact(); | ||
751 | m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
752 | m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction; | ||
753 | m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
754 | m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f; | ||
755 | m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f; | ||
756 | |||
757 | m_materialContacts[(int)Material.Metal, 1] = new d.Contact(); | ||
758 | m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
759 | m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction; | ||
760 | m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce; | ||
761 | m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f; | ||
762 | m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f; | ||
763 | |||
764 | m_materialContacts[(int)Material.Glass, 0] = new d.Contact(); | ||
765 | m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
766 | m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f; | ||
767 | m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f; | ||
768 | m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f; | ||
769 | m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f; | ||
770 | |||
771 | /* | ||
772 | private float nmAvatarObjectContactFriction = 250f; | ||
773 | private float nmAvatarObjectContactBounce = 0.1f; | ||
774 | |||
775 | private float mAvatarObjectContactFriction = 75f; | ||
776 | private float mAvatarObjectContactBounce = 0.1f; | ||
777 | */ | ||
778 | m_materialContacts[(int)Material.Glass, 1] = new d.Contact(); | ||
779 | m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
780 | m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f; | ||
781 | m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f; | ||
782 | m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f; | ||
783 | m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f; | ||
784 | |||
785 | m_materialContacts[(int)Material.Wood, 0] = new d.Contact(); | ||
786 | m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
787 | m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction; | ||
788 | m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
789 | m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f; | ||
790 | m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f; | ||
791 | |||
792 | m_materialContacts[(int)Material.Wood, 1] = new d.Contact(); | ||
793 | m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
794 | m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction; | ||
795 | m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce; | ||
796 | m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f; | ||
797 | m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f; | ||
798 | |||
799 | m_materialContacts[(int)Material.Flesh, 0] = new d.Contact(); | ||
800 | m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
801 | m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction; | ||
802 | m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
803 | m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f; | ||
804 | m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f; | ||
805 | |||
806 | m_materialContacts[(int)Material.Flesh, 1] = new d.Contact(); | ||
807 | m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
808 | m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction; | ||
809 | m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce; | ||
810 | m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f; | ||
811 | m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f; | ||
812 | |||
813 | m_materialContacts[(int)Material.Plastic, 0] = new d.Contact(); | ||
814 | m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
815 | m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction; | ||
816 | m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
817 | m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f; | ||
818 | m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f; | ||
819 | |||
820 | m_materialContacts[(int)Material.Plastic, 1] = new d.Contact(); | ||
821 | m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
822 | m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction; | ||
823 | m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce; | ||
824 | m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f; | ||
825 | m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f; | ||
826 | |||
827 | m_materialContacts[(int)Material.Rubber, 0] = new d.Contact(); | ||
828 | m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
829 | m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction; | ||
830 | m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
831 | m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f; | ||
832 | m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f; | ||
833 | |||
834 | m_materialContacts[(int)Material.Rubber, 1] = new d.Contact(); | ||
835 | m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
836 | m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction; | ||
837 | m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce; | ||
838 | m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f; | ||
839 | m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f; | ||
840 | |||
841 | d.HashSpaceSetLevels(space, HashspaceLow, HashspaceHigh); | ||
842 | |||
843 | // Set the gravity,, don't disable things automatically (we set it explicitly on some things) | ||
844 | |||
845 | d.WorldSetGravity(world, gravityx, gravityy, gravityz); | ||
846 | d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); | ||
847 | |||
848 | d.WorldSetLinearDamping(world, 256f); | ||
849 | d.WorldSetAngularDamping(world, 256f); | ||
850 | d.WorldSetAngularDampingThreshold(world, 256f); | ||
851 | d.WorldSetLinearDampingThreshold(world, 256f); | ||
852 | d.WorldSetMaxAngularSpeed(world, 256f); | ||
853 | |||
854 | d.WorldSetQuickStepNumIterations(world, m_physicsiterations); | ||
855 | //d.WorldSetContactMaxCorrectingVel(world, 1000.0f); | ||
856 | |||
857 | for (int i = 0; i < staticPrimspace.GetLength(0); i++) | ||
858 | { | ||
859 | for (int j = 0; j < staticPrimspace.GetLength(1); j++) | ||
860 | { | ||
861 | staticPrimspace[i, j] = IntPtr.Zero; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | _worldInitialized = true; | ||
866 | } | ||
867 | |||
868 | #region Collision Detection | ||
869 | |||
870 | /// <summary> | ||
871 | /// Collides two geometries. | ||
872 | /// </summary> | ||
873 | /// <returns></returns> | ||
874 | /// <param name='geom1'></param> | ||
875 | /// <param name='geom2'>/param> | ||
876 | /// <param name='maxContacts'></param> | ||
877 | /// <param name='contactsArray'></param> | ||
878 | /// <param name='contactGeomSize'></param> | ||
879 | private int CollideGeoms( | ||
880 | IntPtr geom1, IntPtr geom2, int maxContacts, d.ContactGeom[] contactsArray, int contactGeomSize) | ||
881 | { | ||
882 | int count; | ||
883 | |||
884 | lock (OdeScene.UniversalColliderSyncObject) | ||
885 | { | ||
886 | // We do this inside the lock so that we don't count any delay in acquiring it | ||
887 | if (CollectStats) | ||
888 | m_nativeCollisionStartTick = Util.EnvironmentTickCount(); | ||
889 | |||
890 | count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize); | ||
891 | } | ||
892 | |||
893 | // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably | ||
894 | // negligable | ||
895 | if (CollectStats) | ||
896 | m_stats[ODENativeGeomCollisionFrameMsStatName] | ||
897 | += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); | ||
898 | |||
899 | return count; | ||
900 | } | ||
901 | |||
902 | /// <summary> | ||
903 | /// Collide two spaces or a space and a geometry. | ||
904 | /// </summary> | ||
905 | /// <param name='space1'></param> | ||
906 | /// <param name='space2'>/param> | ||
907 | /// <param name='data'></param> | ||
908 | private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data) | ||
909 | { | ||
910 | if (CollectStats) | ||
911 | { | ||
912 | m_inCollisionTiming = true; | ||
913 | m_nativeCollisionStartTick = Util.EnvironmentTickCount(); | ||
914 | } | ||
915 | |||
916 | d.SpaceCollide2(space1, space2, data, nearCallback); | ||
917 | |||
918 | if (CollectStats && m_inCollisionTiming) | ||
919 | { | ||
920 | m_stats[ODENativeSpaceCollisionFrameMsStatName] | ||
921 | += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); | ||
922 | m_inCollisionTiming = false; | ||
923 | } | ||
924 | } | ||
925 | |||
926 | /// <summary> | ||
927 | /// This is our near callback. A geometry is near a body | ||
928 | /// </summary> | ||
929 | /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param> | ||
930 | /// <param name="g1">a geometry or space</param> | ||
931 | /// <param name="g2">another geometry or space</param> | ||
932 | private void near(IntPtr space, IntPtr g1, IntPtr g2) | ||
933 | { | ||
934 | if (CollectStats && m_inCollisionTiming) | ||
935 | { | ||
936 | m_stats[ODENativeSpaceCollisionFrameMsStatName] | ||
937 | += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); | ||
938 | m_inCollisionTiming = false; | ||
939 | } | ||
940 | |||
941 | // m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space); | ||
942 | // no lock here! It's invoked from within Simulate(), which is thread-locked | ||
943 | |||
944 | // Test if we're colliding a geom with a space. | ||
945 | // If so we have to drill down into the space recursively | ||
946 | |||
947 | if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) | ||
948 | { | ||
949 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
950 | return; | ||
951 | |||
952 | // Separating static prim geometry spaces. | ||
953 | // We'll be calling near recursivly if one | ||
954 | // of them is a space to find all of the | ||
955 | // contact points in the space | ||
956 | try | ||
957 | { | ||
958 | CollideSpaces(g1, g2, IntPtr.Zero); | ||
959 | } | ||
960 | catch (AccessViolationException) | ||
961 | { | ||
962 | m_log.Error("[ODE SCENE]: Unable to collide test a space"); | ||
963 | return; | ||
964 | } | ||
965 | //Colliding a space or a geom with a space or a geom. so drill down | ||
966 | |||
967 | //Collide all geoms in each space.. | ||
968 | //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); | ||
969 | //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); | ||
970 | return; | ||
971 | } | ||
972 | |||
973 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
974 | return; | ||
975 | |||
976 | IntPtr b1 = d.GeomGetBody(g1); | ||
977 | IntPtr b2 = d.GeomGetBody(g2); | ||
978 | |||
979 | // d.GeomClassID id = d.GeomGetClass(g1); | ||
980 | |||
981 | String name1 = null; | ||
982 | String name2 = null; | ||
983 | |||
984 | if (!geom_name_map.TryGetValue(g1, out name1)) | ||
985 | { | ||
986 | name1 = "null"; | ||
987 | } | ||
988 | if (!geom_name_map.TryGetValue(g2, out name2)) | ||
989 | { | ||
990 | name2 = "null"; | ||
991 | } | ||
992 | |||
993 | // Figure out how many contact points we have | ||
994 | int count = 0; | ||
995 | |||
996 | try | ||
997 | { | ||
998 | // Colliding Geom To Geom | ||
999 | // This portion of the function 'was' blatantly ripped off from BoxStack.cs | ||
1000 | |||
1001 | if (g1 == g2) | ||
1002 | return; // Can't collide with yourself | ||
1003 | |||
1004 | if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) | ||
1005 | return; | ||
1006 | |||
1007 | count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.unmanagedSizeOf); | ||
1008 | |||
1009 | // All code after this is only relevant if we have any collisions | ||
1010 | if (count <= 0) | ||
1011 | return; | ||
1012 | |||
1013 | if (count > contacts.Length) | ||
1014 | m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); | ||
1015 | } | ||
1016 | catch (SEHException) | ||
1017 | { | ||
1018 | m_log.Error( | ||
1019 | "[ODE SCENE]: 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."); | ||
1020 | base.TriggerPhysicsBasedRestart(); | ||
1021 | } | ||
1022 | catch (Exception e) | ||
1023 | { | ||
1024 | m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message); | ||
1025 | return; | ||
1026 | } | ||
1027 | |||
1028 | PhysicsActor p1; | ||
1029 | PhysicsActor p2; | ||
1030 | |||
1031 | p1ExpectedPoints = 0; | ||
1032 | p2ExpectedPoints = 0; | ||
1033 | |||
1034 | if (!actor_name_map.TryGetValue(g1, out p1)) | ||
1035 | { | ||
1036 | p1 = PANull; | ||
1037 | } | ||
1038 | |||
1039 | if (!actor_name_map.TryGetValue(g2, out p2)) | ||
1040 | { | ||
1041 | p2 = PANull; | ||
1042 | } | ||
1043 | |||
1044 | ContactPoint maxDepthContact = new ContactPoint(); | ||
1045 | if (p1.CollisionScore + count >= float.MaxValue) | ||
1046 | p1.CollisionScore = 0; | ||
1047 | p1.CollisionScore += count; | ||
1048 | |||
1049 | if (p2.CollisionScore + count >= float.MaxValue) | ||
1050 | p2.CollisionScore = 0; | ||
1051 | p2.CollisionScore += count; | ||
1052 | |||
1053 | for (int i = 0; i < count; i++) | ||
1054 | { | ||
1055 | d.ContactGeom curContact = contacts[i]; | ||
1056 | |||
1057 | if (curContact.depth > maxDepthContact.PenetrationDepth) | ||
1058 | { | ||
1059 | maxDepthContact = new ContactPoint( | ||
1060 | new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), | ||
1061 | new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), | ||
1062 | curContact.depth | ||
1063 | ); | ||
1064 | } | ||
1065 | |||
1066 | //m_log.Warn("[CCOUNT]: " + count); | ||
1067 | IntPtr joint; | ||
1068 | // If we're colliding with terrain, use 'TerrainContact' instead of contact. | ||
1069 | // allows us to have different settings | ||
1070 | |||
1071 | // We only need to test p2 for 'jump crouch purposes' | ||
1072 | if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim) | ||
1073 | { | ||
1074 | // Testing if the collision is at the feet of the avatar | ||
1075 | |||
1076 | //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); | ||
1077 | if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)) | ||
1078 | p2.IsColliding = true; | ||
1079 | } | ||
1080 | else | ||
1081 | { | ||
1082 | p2.IsColliding = true; | ||
1083 | } | ||
1084 | |||
1085 | //if ((framecount % m_returncollisions) == 0) | ||
1086 | |||
1087 | switch (p1.PhysicsActorType) | ||
1088 | { | ||
1089 | case (int)ActorTypes.Agent: | ||
1090 | p1ExpectedPoints = avatarExpectedContacts; | ||
1091 | p2.CollidingObj = true; | ||
1092 | break; | ||
1093 | case (int)ActorTypes.Prim: | ||
1094 | if (p1 != null && p1 is OdePrim) | ||
1095 | p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts; | ||
1096 | |||
1097 | if (p2.Velocity.LengthSquared() > 0.0f) | ||
1098 | p2.CollidingObj = true; | ||
1099 | break; | ||
1100 | case (int)ActorTypes.Unknown: | ||
1101 | p2.CollidingGround = true; | ||
1102 | break; | ||
1103 | default: | ||
1104 | p2.CollidingGround = true; | ||
1105 | break; | ||
1106 | } | ||
1107 | |||
1108 | // we don't want prim or avatar to explode | ||
1109 | |||
1110 | #region InterPenetration Handling - Unintended physics explosions | ||
1111 | |||
1112 | if (curContact.depth >= 0.08f) | ||
1113 | { | ||
1114 | if (curContact.depth >= 1.00f) | ||
1115 | { | ||
1116 | //m_log.Info("[P]: " + contact.depth.ToString()); | ||
1117 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && | ||
1118 | p1.PhysicsActorType == (int) ActorTypes.Unknown) || | ||
1119 | (p1.PhysicsActorType == (int) ActorTypes.Agent && | ||
1120 | p2.PhysicsActorType == (int) ActorTypes.Unknown)) | ||
1121 | { | ||
1122 | if (p2.PhysicsActorType == (int) ActorTypes.Agent) | ||
1123 | { | ||
1124 | if (p2 is OdeCharacter) | ||
1125 | { | ||
1126 | OdeCharacter character = (OdeCharacter) p2; | ||
1127 | |||
1128 | //p2.CollidingObj = true; | ||
1129 | curContact.depth = 0.00000003f; | ||
1130 | p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); | ||
1131 | curContact.pos = | ||
1132 | new d.Vector3(curContact.pos.X + (p1.Size.X/2), | ||
1133 | curContact.pos.Y + (p1.Size.Y/2), | ||
1134 | curContact.pos.Z + (p1.Size.Z/2)); | ||
1135 | character.SetPidStatus(true); | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) | ||
1140 | { | ||
1141 | if (p1 is OdeCharacter) | ||
1142 | { | ||
1143 | OdeCharacter character = (OdeCharacter) p1; | ||
1144 | |||
1145 | //p2.CollidingObj = true; | ||
1146 | curContact.depth = 0.00000003f; | ||
1147 | p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f); | ||
1148 | curContact.pos = | ||
1149 | new d.Vector3(curContact.pos.X + (p1.Size.X/2), | ||
1150 | curContact.pos.Y + (p1.Size.Y/2), | ||
1151 | curContact.pos.Z + (p1.Size.Z/2)); | ||
1152 | character.SetPidStatus(true); | ||
1153 | } | ||
1154 | } | ||
1155 | } | ||
1156 | } | ||
1157 | } | ||
1158 | |||
1159 | #endregion | ||
1160 | |||
1161 | // Logic for collision handling | ||
1162 | // Note, that if *all* contacts are skipped (VolumeDetect) | ||
1163 | // The prim still detects (and forwards) collision events but | ||
1164 | // appears to be phantom for the world | ||
1165 | Boolean skipThisContact = false; | ||
1166 | |||
1167 | if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) | ||
1168 | skipThisContact = true; // No collision on volume detect prims | ||
1169 | |||
1170 | if (av_av_collisions_off) | ||
1171 | if ((p1 is OdeCharacter) && (p2 is OdeCharacter)) | ||
1172 | skipThisContact = true; | ||
1173 | |||
1174 | if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) | ||
1175 | skipThisContact = true; // No collision on volume detect prims | ||
1176 | |||
1177 | if (!skipThisContact && curContact.depth < 0f) | ||
1178 | skipThisContact = true; | ||
1179 | |||
1180 | if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) | ||
1181 | skipThisContact = true; | ||
1182 | |||
1183 | const int maxContactsbeforedeath = 4000; | ||
1184 | joint = IntPtr.Zero; | ||
1185 | |||
1186 | if (!skipThisContact) | ||
1187 | { | ||
1188 | _perloopContact.Add(curContact); | ||
1189 | |||
1190 | if (name1 == "Terrain" || name2 == "Terrain") | ||
1191 | { | ||
1192 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && | ||
1193 | (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) | ||
1194 | { | ||
1195 | p2ExpectedPoints = avatarExpectedContacts; | ||
1196 | // Avatar is moving on terrain, use the movement terrain contact | ||
1197 | AvatarMovementTerrainContact.geom = curContact; | ||
1198 | |||
1199 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1200 | { | ||
1201 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); | ||
1202 | m_global_contactcount++; | ||
1203 | } | ||
1204 | } | ||
1205 | else | ||
1206 | { | ||
1207 | if (p2.PhysicsActorType == (int)ActorTypes.Agent) | ||
1208 | { | ||
1209 | p2ExpectedPoints = avatarExpectedContacts; | ||
1210 | // Avatar is standing on terrain, use the non moving terrain contact | ||
1211 | TerrainContact.geom = curContact; | ||
1212 | |||
1213 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1214 | { | ||
1215 | joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); | ||
1216 | m_global_contactcount++; | ||
1217 | } | ||
1218 | } | ||
1219 | else | ||
1220 | { | ||
1221 | if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim) | ||
1222 | { | ||
1223 | // prim prim contact | ||
1224 | // int pj294950 = 0; | ||
1225 | int movintYN = 0; | ||
1226 | int material = (int) Material.Wood; | ||
1227 | // prim terrain contact | ||
1228 | if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) | ||
1229 | { | ||
1230 | movintYN = 1; | ||
1231 | } | ||
1232 | |||
1233 | if (p2 is OdePrim) | ||
1234 | { | ||
1235 | material = ((OdePrim) p2).m_material; | ||
1236 | p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; | ||
1237 | } | ||
1238 | |||
1239 | // Unnessesary because p1 is defined above | ||
1240 | //if (p1 is OdePrim) | ||
1241 | // { | ||
1242 | // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts; | ||
1243 | // } | ||
1244 | //m_log.DebugFormat("Material: {0}", material); | ||
1245 | |||
1246 | m_materialContacts[material, movintYN].geom = curContact; | ||
1247 | |||
1248 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1249 | { | ||
1250 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); | ||
1251 | m_global_contactcount++; | ||
1252 | } | ||
1253 | } | ||
1254 | else | ||
1255 | { | ||
1256 | int movintYN = 0; | ||
1257 | // prim terrain contact | ||
1258 | if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) | ||
1259 | { | ||
1260 | movintYN = 1; | ||
1261 | } | ||
1262 | |||
1263 | int material = (int)Material.Wood; | ||
1264 | |||
1265 | if (p2 is OdePrim) | ||
1266 | { | ||
1267 | material = ((OdePrim)p2).m_material; | ||
1268 | p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; | ||
1269 | } | ||
1270 | |||
1271 | //m_log.DebugFormat("Material: {0}", material); | ||
1272 | m_materialContacts[material, movintYN].geom = curContact; | ||
1273 | |||
1274 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1275 | { | ||
1276 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); | ||
1277 | m_global_contactcount++; | ||
1278 | } | ||
1279 | } | ||
1280 | } | ||
1281 | } | ||
1282 | //if (p2.PhysicsActorType == (int)ActorTypes.Prim) | ||
1283 | //{ | ||
1284 | //m_log.Debug("[PHYSICS]: prim contacting with ground"); | ||
1285 | //} | ||
1286 | } | ||
1287 | else if (name1 == "Water" || name2 == "Water") | ||
1288 | { | ||
1289 | /* | ||
1290 | if ((p2.PhysicsActorType == (int) ActorTypes.Prim)) | ||
1291 | { | ||
1292 | } | ||
1293 | else | ||
1294 | { | ||
1295 | } | ||
1296 | */ | ||
1297 | //WaterContact.surface.soft_cfm = 0.0000f; | ||
1298 | //WaterContact.surface.soft_erp = 0.00000f; | ||
1299 | if (curContact.depth > 0.1f) | ||
1300 | { | ||
1301 | curContact.depth *= 52; | ||
1302 | //contact.normal = new d.Vector3(0, 0, 1); | ||
1303 | //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f); | ||
1304 | } | ||
1305 | |||
1306 | WaterContact.geom = curContact; | ||
1307 | |||
1308 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1309 | { | ||
1310 | joint = d.JointCreateContact(world, contactgroup, ref WaterContact); | ||
1311 | m_global_contactcount++; | ||
1312 | } | ||
1313 | //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth); | ||
1314 | } | ||
1315 | else | ||
1316 | { | ||
1317 | if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) | ||
1318 | { | ||
1319 | p2ExpectedPoints = avatarExpectedContacts; | ||
1320 | if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) | ||
1321 | { | ||
1322 | // Avatar is moving on a prim, use the Movement prim contact | ||
1323 | AvatarMovementprimContact.geom = curContact; | ||
1324 | |||
1325 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1326 | { | ||
1327 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); | ||
1328 | m_global_contactcount++; | ||
1329 | } | ||
1330 | } | ||
1331 | else | ||
1332 | { | ||
1333 | // Avatar is standing still on a prim, use the non movement contact | ||
1334 | contact.geom = curContact; | ||
1335 | |||
1336 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1337 | { | ||
1338 | joint = d.JointCreateContact(world, contactgroup, ref contact); | ||
1339 | m_global_contactcount++; | ||
1340 | } | ||
1341 | } | ||
1342 | } | ||
1343 | else if (p2.PhysicsActorType == (int)ActorTypes.Prim) | ||
1344 | { | ||
1345 | //p1.PhysicsActorType | ||
1346 | int material = (int)Material.Wood; | ||
1347 | |||
1348 | if (p2 is OdePrim) | ||
1349 | { | ||
1350 | material = ((OdePrim)p2).m_material; | ||
1351 | p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; | ||
1352 | } | ||
1353 | |||
1354 | //m_log.DebugFormat("Material: {0}", material); | ||
1355 | m_materialContacts[material, 0].geom = curContact; | ||
1356 | |||
1357 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1358 | { | ||
1359 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]); | ||
1360 | m_global_contactcount++; | ||
1361 | } | ||
1362 | } | ||
1363 | } | ||
1364 | |||
1365 | if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! | ||
1366 | { | ||
1367 | d.JointAttach(joint, b1, b2); | ||
1368 | m_global_contactcount++; | ||
1369 | } | ||
1370 | } | ||
1371 | |||
1372 | collision_accounting_events(p1, p2, maxDepthContact); | ||
1373 | |||
1374 | if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle)) | ||
1375 | { | ||
1376 | // If there are more then 3 contact points, it's likely | ||
1377 | // that we've got a pile of objects, so ... | ||
1378 | // We don't want to send out hundreds of terse updates over and over again | ||
1379 | // so lets throttle them and send them again after it's somewhat sorted out. | ||
1380 | p2.ThrottleUpdates = true; | ||
1381 | } | ||
1382 | //m_log.Debug(count.ToString()); | ||
1383 | //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); | ||
1384 | } | ||
1385 | } | ||
1386 | |||
1387 | private bool checkDupe(d.ContactGeom contactGeom, int atype) | ||
1388 | { | ||
1389 | if (!m_filterCollisions) | ||
1390 | return false; | ||
1391 | |||
1392 | bool result = false; | ||
1393 | |||
1394 | ActorTypes at = (ActorTypes)atype; | ||
1395 | |||
1396 | foreach (d.ContactGeom contact in _perloopContact) | ||
1397 | { | ||
1398 | //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2)) | ||
1399 | //{ | ||
1400 | // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2) | ||
1401 | if (at == ActorTypes.Agent) | ||
1402 | { | ||
1403 | if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) | ||
1404 | && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) | ||
1405 | && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f))) | ||
1406 | { | ||
1407 | if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) | ||
1408 | { | ||
1409 | result = true; | ||
1410 | break; | ||
1411 | } | ||
1412 | } | ||
1413 | } | ||
1414 | else if (at == ActorTypes.Prim) | ||
1415 | { | ||
1416 | if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f))) | ||
1417 | { | ||
1418 | if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) | ||
1419 | { | ||
1420 | if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) | ||
1421 | { | ||
1422 | result = true; | ||
1423 | break; | ||
1424 | } | ||
1425 | } | ||
1426 | //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); | ||
1427 | //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); | ||
1428 | } | ||
1429 | } | ||
1430 | } | ||
1431 | |||
1432 | return result; | ||
1433 | } | ||
1434 | |||
1435 | private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) | ||
1436 | { | ||
1437 | // obj1LocalID = 0; | ||
1438 | //returncollisions = false; | ||
1439 | obj2LocalID = 0; | ||
1440 | //ctype = 0; | ||
1441 | //cStartStop = 0; | ||
1442 | // if (!p2.SubscribedEvents() && !p1.SubscribedEvents()) | ||
1443 | // return; | ||
1444 | bool p1events = p1.SubscribedEvents(); | ||
1445 | bool p2events = p2.SubscribedEvents(); | ||
1446 | |||
1447 | if (p1.IsVolumeDtc) | ||
1448 | p2events = false; | ||
1449 | if (p2.IsVolumeDtc) | ||
1450 | p1events = false; | ||
1451 | |||
1452 | if (!p2events && !p1events) | ||
1453 | return; | ||
1454 | |||
1455 | Vector3 vel = Vector3.Zero; | ||
1456 | if (p2 != null && p2.IsPhysical) | ||
1457 | vel = p2.Velocity; | ||
1458 | |||
1459 | if (p1 != null && p1.IsPhysical) | ||
1460 | vel -= p1.Velocity; | ||
1461 | |||
1462 | contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal); | ||
1463 | |||
1464 | switch ((ActorTypes)p2.PhysicsActorType) | ||
1465 | { | ||
1466 | case ActorTypes.Agent: | ||
1467 | cc2 = (OdeCharacter)p2; | ||
1468 | |||
1469 | // obj1LocalID = cc2.m_localID; | ||
1470 | switch ((ActorTypes)p1.PhysicsActorType) | ||
1471 | { | ||
1472 | case ActorTypes.Agent: | ||
1473 | cc1 = (OdeCharacter)p1; | ||
1474 | obj2LocalID = cc1.LocalID; | ||
1475 | cc1.AddCollisionEvent(cc2.LocalID, contact); | ||
1476 | break; | ||
1477 | |||
1478 | case ActorTypes.Prim: | ||
1479 | if (p1 is OdePrim) | ||
1480 | { | ||
1481 | cp1 = (OdePrim) p1; | ||
1482 | obj2LocalID = cp1.LocalID; | ||
1483 | cp1.AddCollisionEvent(cc2.LocalID, contact); | ||
1484 | } | ||
1485 | break; | ||
1486 | |||
1487 | case ActorTypes.Ground: | ||
1488 | case ActorTypes.Unknown: | ||
1489 | obj2LocalID = 0; | ||
1490 | break; | ||
1491 | } | ||
1492 | |||
1493 | cc2.AddCollisionEvent(obj2LocalID, contact); | ||
1494 | break; | ||
1495 | |||
1496 | case ActorTypes.Prim: | ||
1497 | |||
1498 | if (p2 is OdePrim) | ||
1499 | { | ||
1500 | cp2 = (OdePrim) p2; | ||
1501 | |||
1502 | // obj1LocalID = cp2.m_localID; | ||
1503 | switch ((ActorTypes) p1.PhysicsActorType) | ||
1504 | { | ||
1505 | case ActorTypes.Agent: | ||
1506 | if (p1 is OdeCharacter) | ||
1507 | { | ||
1508 | cc1 = (OdeCharacter) p1; | ||
1509 | obj2LocalID = cc1.LocalID; | ||
1510 | cc1.AddCollisionEvent(cp2.LocalID, contact); | ||
1511 | } | ||
1512 | break; | ||
1513 | case ActorTypes.Prim: | ||
1514 | |||
1515 | if (p1 is OdePrim) | ||
1516 | { | ||
1517 | cp1 = (OdePrim) p1; | ||
1518 | obj2LocalID = cp1.LocalID; | ||
1519 | cp1.AddCollisionEvent(cp2.LocalID, contact); | ||
1520 | } | ||
1521 | break; | ||
1522 | |||
1523 | case ActorTypes.Ground: | ||
1524 | case ActorTypes.Unknown: | ||
1525 | obj2LocalID = 0; | ||
1526 | break; | ||
1527 | } | ||
1528 | |||
1529 | cp2.AddCollisionEvent(obj2LocalID, contact); | ||
1530 | } | ||
1531 | break; | ||
1532 | } | ||
1533 | } | ||
1534 | /// <summary> | ||
1535 | /// This is our collision testing routine in ODE | ||
1536 | /// </summary> | ||
1537 | private void collision_optimized() | ||
1538 | { | ||
1539 | _perloopContact.Clear(); | ||
1540 | |||
1541 | foreach (OdeCharacter chr in _characters) | ||
1542 | { | ||
1543 | // Reset the collision values to false | ||
1544 | // since we don't know if we're colliding yet | ||
1545 | if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) | ||
1546 | continue; | ||
1547 | |||
1548 | chr.IsColliding = false; | ||
1549 | chr.CollidingGround = false; | ||
1550 | chr.CollidingObj = false; | ||
1551 | |||
1552 | // Test the avatar's geometry for collision with the space | ||
1553 | // This will return near and the space that they are the closest to | ||
1554 | // And we'll run this again against the avatar and the space segment | ||
1555 | // This will return with a bunch of possible objects in the space segment | ||
1556 | // and we'll run it again on all of them. | ||
1557 | try | ||
1558 | { | ||
1559 | CollideSpaces(space, chr.Shell, IntPtr.Zero); | ||
1560 | } | ||
1561 | catch (AccessViolationException) | ||
1562 | { | ||
1563 | m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", PhysicsSceneName); | ||
1564 | } | ||
1565 | |||
1566 | //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); | ||
1567 | //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) | ||
1568 | //{ | ||
1569 | //chr.Position.Z = terrainheight + 10.0f; | ||
1570 | //forcedZ = true; | ||
1571 | //} | ||
1572 | } | ||
1573 | |||
1574 | if (CollectStats) | ||
1575 | { | ||
1576 | m_tempAvatarCollisionsThisFrame = _perloopContact.Count; | ||
1577 | m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame; | ||
1578 | } | ||
1579 | |||
1580 | List<OdePrim> removeprims = null; | ||
1581 | foreach (OdePrim chr in _activeprims) | ||
1582 | { | ||
1583 | if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) | ||
1584 | { | ||
1585 | try | ||
1586 | { | ||
1587 | lock (chr) | ||
1588 | { | ||
1589 | if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) | ||
1590 | { | ||
1591 | CollideSpaces(space, chr.prim_geom, IntPtr.Zero); | ||
1592 | } | ||
1593 | else | ||
1594 | { | ||
1595 | if (removeprims == null) | ||
1596 | { | ||
1597 | removeprims = new List<OdePrim>(); | ||
1598 | } | ||
1599 | removeprims.Add(chr); | ||
1600 | m_log.Error( | ||
1601 | "[ODE SCENE]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!"); | ||
1602 | } | ||
1603 | } | ||
1604 | } | ||
1605 | catch (AccessViolationException) | ||
1606 | { | ||
1607 | m_log.Error("[ODE SCENE]: Unable to space collide"); | ||
1608 | } | ||
1609 | } | ||
1610 | } | ||
1611 | |||
1612 | if (CollectStats) | ||
1613 | m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame; | ||
1614 | |||
1615 | if (removeprims != null) | ||
1616 | { | ||
1617 | foreach (OdePrim chr in removeprims) | ||
1618 | { | ||
1619 | _activeprims.Remove(chr); | ||
1620 | } | ||
1621 | } | ||
1622 | } | ||
1623 | |||
1624 | #endregion | ||
1625 | |||
1626 | // Recovered for use by fly height. Kitto Flora | ||
1627 | internal float GetTerrainHeightAtXY(float x, float y) | ||
1628 | { | ||
1629 | IntPtr heightFieldGeom = IntPtr.Zero; | ||
1630 | int offsetX = 0; | ||
1631 | int offsetY = 0; | ||
1632 | |||
1633 | if(RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom)) | ||
1634 | { | ||
1635 | if (heightFieldGeom != IntPtr.Zero) | ||
1636 | { | ||
1637 | if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom)) | ||
1638 | { | ||
1639 | |||
1640 | int index; | ||
1641 | |||
1642 | |||
1643 | if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y || | ||
1644 | (int)x < 0.001f || (int)y < 0.001f) | ||
1645 | return 0; | ||
1646 | |||
1647 | x = x - offsetX + 1f; | ||
1648 | y = y - offsetY + 1f; | ||
1649 | |||
1650 | // map is rotated | ||
1651 | index = (int)x * ((int)m_regionHeight + 3) + (int)y; | ||
1652 | |||
1653 | if (index < TerrainHeightFieldHeights[heightFieldGeom].Length) | ||
1654 | { | ||
1655 | //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]); | ||
1656 | return (float)TerrainHeightFieldHeights[heightFieldGeom][index]; | ||
1657 | } | ||
1658 | |||
1659 | else | ||
1660 | return 0f; | ||
1661 | } | ||
1662 | else | ||
1663 | { | ||
1664 | return 0f; | ||
1665 | } | ||
1666 | |||
1667 | } | ||
1668 | else | ||
1669 | { | ||
1670 | return 0f; | ||
1671 | } | ||
1672 | |||
1673 | } | ||
1674 | else | ||
1675 | { | ||
1676 | return 0f; | ||
1677 | } | ||
1678 | } | ||
1679 | // End recovered. Kitto Flora | ||
1680 | |||
1681 | /// <summary> | ||
1682 | /// Add actor to the list that should receive collision events in the simulate loop. | ||
1683 | /// </summary> | ||
1684 | /// <param name="obj"></param> | ||
1685 | internal void AddCollisionEventReporting(PhysicsActor obj) | ||
1686 | { | ||
1687 | // m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID); | ||
1688 | |||
1689 | lock (m_collisionEventActorsChanges) | ||
1690 | m_collisionEventActorsChanges[obj.LocalID] = obj; | ||
1691 | } | ||
1692 | |||
1693 | /// <summary> | ||
1694 | /// Remove actor from the list that should receive collision events in the simulate loop. | ||
1695 | /// </summary> | ||
1696 | /// <param name="obj"></param> | ||
1697 | internal void RemoveCollisionEventReporting(PhysicsActor obj) | ||
1698 | { | ||
1699 | // m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID); | ||
1700 | |||
1701 | lock (m_collisionEventActorsChanges) | ||
1702 | m_collisionEventActorsChanges[obj.LocalID] = null; | ||
1703 | } | ||
1704 | |||
1705 | #region Add/Remove Entities | ||
1706 | |||
1707 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) | ||
1708 | { | ||
1709 | d.AllocateODEDataForThread(0); | ||
1710 | |||
1711 | OdeCharacter newAv | ||
1712 | = new OdeCharacter( | ||
1713 | avName, this, position, velocity, size, avPIDD, avPIDP, | ||
1714 | avCapRadius, avStandupTensor, avDensity, | ||
1715 | avMovementDivisorWalk, avMovementDivisorRun); | ||
1716 | |||
1717 | newAv.Flying = isFlying; | ||
1718 | newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; | ||
1719 | newAv.m_avatarplanted = avplanted; | ||
1720 | |||
1721 | return newAv; | ||
1722 | } | ||
1723 | |||
1724 | public override void RemoveAvatar(PhysicsActor actor) | ||
1725 | { | ||
1726 | // m_log.DebugFormat( | ||
1727 | // "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}", | ||
1728 | // actor.Name, actor.LocalID, Name); | ||
1729 | |||
1730 | lock (OdeLock) | ||
1731 | { | ||
1732 | d.AllocateODEDataForThread(0); | ||
1733 | |||
1734 | ((OdeCharacter) actor).Destroy(); | ||
1735 | } | ||
1736 | } | ||
1737 | |||
1738 | internal void AddCharacter(OdeCharacter chr) | ||
1739 | { | ||
1740 | chr.m_avatarplanted = avplanted; | ||
1741 | if (!_characters.Contains(chr)) | ||
1742 | { | ||
1743 | _characters.Add(chr); | ||
1744 | |||
1745 | // m_log.DebugFormat( | ||
1746 | // "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}", | ||
1747 | // chr.Name, chr.LocalID, Name, _characters.Count); | ||
1748 | |||
1749 | if (chr.bad) | ||
1750 | m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid); | ||
1751 | } | ||
1752 | else | ||
1753 | { | ||
1754 | m_log.ErrorFormat( | ||
1755 | "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!", | ||
1756 | chr.Name, chr.LocalID); | ||
1757 | } | ||
1758 | } | ||
1759 | |||
1760 | internal void RemoveCharacter(OdeCharacter chr) | ||
1761 | { | ||
1762 | if (_characters.Contains(chr)) | ||
1763 | { | ||
1764 | _characters.Remove(chr); | ||
1765 | |||
1766 | // m_log.DebugFormat( | ||
1767 | // "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}", | ||
1768 | // chr.Name, chr.LocalID, Name, _characters.Count); | ||
1769 | } | ||
1770 | else | ||
1771 | { | ||
1772 | m_log.ErrorFormat( | ||
1773 | "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!", | ||
1774 | chr.Name, chr.LocalID); | ||
1775 | } | ||
1776 | } | ||
1777 | |||
1778 | private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, | ||
1779 | PrimitiveBaseShape pbs, bool isphysical, uint localID) | ||
1780 | { | ||
1781 | Vector3 pos = position; | ||
1782 | Vector3 siz = size; | ||
1783 | Quaternion rot = rotation; | ||
1784 | |||
1785 | |||
1786 | OdePrim newPrim; | ||
1787 | lock (OdeLock) | ||
1788 | { | ||
1789 | d.AllocateODEDataForThread(0); | ||
1790 | newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical); | ||
1791 | |||
1792 | lock (_prims) | ||
1793 | _prims.Add(newPrim); | ||
1794 | } | ||
1795 | newPrim.LocalID = localID; | ||
1796 | return newPrim; | ||
1797 | } | ||
1798 | |||
1799 | /// <summary> | ||
1800 | /// Make this prim subject to physics. | ||
1801 | /// </summary> | ||
1802 | /// <param name="prim"></param> | ||
1803 | internal void ActivatePrim(OdePrim prim) | ||
1804 | { | ||
1805 | // adds active prim.. (ones that should be iterated over in collisions_optimized | ||
1806 | if (!_activeprims.Contains(prim)) | ||
1807 | _activeprims.Add(prim); | ||
1808 | //else | ||
1809 | // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent"); | ||
1810 | } | ||
1811 | |||
1812 | public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | ||
1813 | Vector3 size, Quaternion rotation, bool isPhysical, uint localid) | ||
1814 | { | ||
1815 | // m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name); | ||
1816 | |||
1817 | return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid); | ||
1818 | } | ||
1819 | |||
1820 | public override float TimeDilation | ||
1821 | { | ||
1822 | get { return m_timeDilation; } | ||
1823 | } | ||
1824 | |||
1825 | public override bool SupportsNINJAJoints | ||
1826 | { | ||
1827 | get { return m_NINJA_physics_joints_enabled; } | ||
1828 | } | ||
1829 | |||
1830 | // internal utility function: must be called within a lock (OdeLock) | ||
1831 | private void InternalAddActiveJoint(PhysicsJoint joint) | ||
1832 | { | ||
1833 | activeJoints.Add(joint); | ||
1834 | SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint); | ||
1835 | } | ||
1836 | |||
1837 | // internal utility function: must be called within a lock (OdeLock) | ||
1838 | private void InternalAddPendingJoint(OdePhysicsJoint joint) | ||
1839 | { | ||
1840 | pendingJoints.Add(joint); | ||
1841 | SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint); | ||
1842 | } | ||
1843 | |||
1844 | // internal utility function: must be called within a lock (OdeLock) | ||
1845 | private void InternalRemovePendingJoint(PhysicsJoint joint) | ||
1846 | { | ||
1847 | pendingJoints.Remove(joint); | ||
1848 | SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene); | ||
1849 | } | ||
1850 | |||
1851 | // internal utility function: must be called within a lock (OdeLock) | ||
1852 | private void InternalRemoveActiveJoint(PhysicsJoint joint) | ||
1853 | { | ||
1854 | activeJoints.Remove(joint); | ||
1855 | SOPName_to_activeJoint.Remove(joint.ObjectNameInScene); | ||
1856 | } | ||
1857 | |||
1858 | public override void DumpJointInfo() | ||
1859 | { | ||
1860 | string hdr = "[NINJA] JOINTINFO: "; | ||
1861 | foreach (PhysicsJoint j in pendingJoints) | ||
1862 | { | ||
1863 | m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); | ||
1864 | } | ||
1865 | m_log.Debug(hdr + pendingJoints.Count + " total pending joints"); | ||
1866 | foreach (string jointName in SOPName_to_pendingJoint.Keys) | ||
1867 | { | ||
1868 | m_log.Debug(hdr + " pending joints dict contains Name: " + jointName); | ||
1869 | } | ||
1870 | m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries"); | ||
1871 | foreach (PhysicsJoint j in activeJoints) | ||
1872 | { | ||
1873 | m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); | ||
1874 | } | ||
1875 | m_log.Debug(hdr + activeJoints.Count + " total active joints"); | ||
1876 | foreach (string jointName in SOPName_to_activeJoint.Keys) | ||
1877 | { | ||
1878 | m_log.Debug(hdr + " active joints dict contains Name: " + jointName); | ||
1879 | } | ||
1880 | m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries"); | ||
1881 | |||
1882 | m_log.Debug(hdr + " Per-body joint connectivity information follows."); | ||
1883 | m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints."); | ||
1884 | foreach (string actorName in joints_connecting_actor.Keys) | ||
1885 | { | ||
1886 | m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it"); | ||
1887 | foreach (PhysicsJoint j in joints_connecting_actor[actorName]) | ||
1888 | { | ||
1889 | m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); | ||
1890 | } | ||
1891 | m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor"); | ||
1892 | } | ||
1893 | } | ||
1894 | |||
1895 | public override void RequestJointDeletion(string ObjectNameInScene) | ||
1896 | { | ||
1897 | lock (externalJointRequestsLock) | ||
1898 | { | ||
1899 | if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously | ||
1900 | { | ||
1901 | requestedJointsToBeDeleted.Add(ObjectNameInScene); | ||
1902 | } | ||
1903 | } | ||
1904 | } | ||
1905 | |||
1906 | private void DeleteRequestedJoints() | ||
1907 | { | ||
1908 | List<string> myRequestedJointsToBeDeleted; | ||
1909 | lock (externalJointRequestsLock) | ||
1910 | { | ||
1911 | // make a local copy of the shared list for processing (threading issues) | ||
1912 | myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted); | ||
1913 | } | ||
1914 | |||
1915 | foreach (string jointName in myRequestedJointsToBeDeleted) | ||
1916 | { | ||
1917 | lock (OdeLock) | ||
1918 | { | ||
1919 | //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName); | ||
1920 | if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName)) | ||
1921 | { | ||
1922 | OdePhysicsJoint joint = null; | ||
1923 | if (SOPName_to_activeJoint.ContainsKey(jointName)) | ||
1924 | { | ||
1925 | joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint; | ||
1926 | InternalRemoveActiveJoint(joint); | ||
1927 | } | ||
1928 | else if (SOPName_to_pendingJoint.ContainsKey(jointName)) | ||
1929 | { | ||
1930 | joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint; | ||
1931 | InternalRemovePendingJoint(joint); | ||
1932 | } | ||
1933 | |||
1934 | if (joint != null) | ||
1935 | { | ||
1936 | //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames); | ||
1937 | for (int iBodyName = 0; iBodyName < 2; iBodyName++) | ||
1938 | { | ||
1939 | string bodyName = joint.BodyNames[iBodyName]; | ||
1940 | if (bodyName != "NULL") | ||
1941 | { | ||
1942 | joints_connecting_actor[bodyName].Remove(joint); | ||
1943 | if (joints_connecting_actor[bodyName].Count == 0) | ||
1944 | { | ||
1945 | joints_connecting_actor.Remove(bodyName); | ||
1946 | } | ||
1947 | } | ||
1948 | } | ||
1949 | |||
1950 | DoJointDeactivated(joint); | ||
1951 | if (joint.jointID != IntPtr.Zero) | ||
1952 | { | ||
1953 | d.JointDestroy(joint.jointID); | ||
1954 | joint.jointID = IntPtr.Zero; | ||
1955 | //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName); | ||
1956 | } | ||
1957 | else | ||
1958 | { | ||
1959 | //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName); | ||
1960 | } | ||
1961 | } | ||
1962 | else | ||
1963 | { | ||
1964 | // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName); | ||
1965 | } | ||
1966 | } | ||
1967 | else | ||
1968 | { | ||
1969 | // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName); | ||
1970 | } | ||
1971 | } | ||
1972 | } | ||
1973 | |||
1974 | // remove processed joints from the shared list | ||
1975 | lock (externalJointRequestsLock) | ||
1976 | { | ||
1977 | foreach (string jointName in myRequestedJointsToBeDeleted) | ||
1978 | { | ||
1979 | requestedJointsToBeDeleted.Remove(jointName); | ||
1980 | } | ||
1981 | } | ||
1982 | } | ||
1983 | |||
1984 | // for pending joints we don't know if their associated bodies exist yet or not. | ||
1985 | // the joint is actually created during processing of the taints | ||
1986 | private void CreateRequestedJoints() | ||
1987 | { | ||
1988 | List<PhysicsJoint> myRequestedJointsToBeCreated; | ||
1989 | lock (externalJointRequestsLock) | ||
1990 | { | ||
1991 | // make a local copy of the shared list for processing (threading issues) | ||
1992 | myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated); | ||
1993 | } | ||
1994 | |||
1995 | foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) | ||
1996 | { | ||
1997 | lock (OdeLock) | ||
1998 | { | ||
1999 | if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null) | ||
2000 | { | ||
2001 | DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); | ||
2002 | continue; | ||
2003 | } | ||
2004 | if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null) | ||
2005 | { | ||
2006 | DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); | ||
2007 | continue; | ||
2008 | } | ||
2009 | |||
2010 | InternalAddPendingJoint(joint as OdePhysicsJoint); | ||
2011 | |||
2012 | if (joint.BodyNames.Count >= 2) | ||
2013 | { | ||
2014 | for (int iBodyName = 0; iBodyName < 2; iBodyName++) | ||
2015 | { | ||
2016 | string bodyName = joint.BodyNames[iBodyName]; | ||
2017 | if (bodyName != "NULL") | ||
2018 | { | ||
2019 | if (!joints_connecting_actor.ContainsKey(bodyName)) | ||
2020 | { | ||
2021 | joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>()); | ||
2022 | } | ||
2023 | joints_connecting_actor[bodyName].Add(joint); | ||
2024 | } | ||
2025 | } | ||
2026 | } | ||
2027 | } | ||
2028 | } | ||
2029 | |||
2030 | // remove processed joints from shared list | ||
2031 | lock (externalJointRequestsLock) | ||
2032 | { | ||
2033 | foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) | ||
2034 | { | ||
2035 | requestedJointsToBeCreated.Remove(joint); | ||
2036 | } | ||
2037 | } | ||
2038 | } | ||
2039 | |||
2040 | /// <summary> | ||
2041 | /// Add a request for joint creation. | ||
2042 | /// </summary> | ||
2043 | /// <remarks> | ||
2044 | /// this joint will just be added to a waiting list that is NOT processed during the main | ||
2045 | /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests. | ||
2046 | /// </remarks> | ||
2047 | /// <param name="objectNameInScene"></param> | ||
2048 | /// <param name="jointType"></param> | ||
2049 | /// <param name="position"></param> | ||
2050 | /// <param name="rotation"></param> | ||
2051 | /// <param name="parms"></param> | ||
2052 | /// <param name="bodyNames"></param> | ||
2053 | /// <param name="trackedBodyName"></param> | ||
2054 | /// <param name="localRotation"></param> | ||
2055 | /// <returns></returns> | ||
2056 | public override PhysicsJoint RequestJointCreation( | ||
2057 | string objectNameInScene, PhysicsJointType jointType, Vector3 position, | ||
2058 | Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation) | ||
2059 | { | ||
2060 | OdePhysicsJoint joint = new OdePhysicsJoint(); | ||
2061 | joint.ObjectNameInScene = objectNameInScene; | ||
2062 | joint.Type = jointType; | ||
2063 | joint.Position = position; | ||
2064 | joint.Rotation = rotation; | ||
2065 | joint.RawParams = parms; | ||
2066 | joint.BodyNames = new List<string>(bodyNames); | ||
2067 | joint.TrackedBodyName = trackedBodyName; | ||
2068 | joint.LocalRotation = localRotation; | ||
2069 | joint.jointID = IntPtr.Zero; | ||
2070 | joint.ErrorMessageCount = 0; | ||
2071 | |||
2072 | lock (externalJointRequestsLock) | ||
2073 | { | ||
2074 | if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice | ||
2075 | { | ||
2076 | requestedJointsToBeCreated.Add(joint); | ||
2077 | } | ||
2078 | } | ||
2079 | |||
2080 | return joint; | ||
2081 | } | ||
2082 | |||
2083 | private void RemoveAllJointsConnectedToActor(PhysicsActor actor) | ||
2084 | { | ||
2085 | //m_log.Debug("RemoveAllJointsConnectedToActor: start"); | ||
2086 | if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null) | ||
2087 | { | ||
2088 | List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>(); | ||
2089 | //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism) | ||
2090 | foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName]) | ||
2091 | { | ||
2092 | jointsToRemove.Add(j); | ||
2093 | } | ||
2094 | foreach (PhysicsJoint j in jointsToRemove) | ||
2095 | { | ||
2096 | //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene); | ||
2097 | RequestJointDeletion(j.ObjectNameInScene); | ||
2098 | //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene); | ||
2099 | j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing) | ||
2100 | } | ||
2101 | } | ||
2102 | } | ||
2103 | |||
2104 | public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) | ||
2105 | { | ||
2106 | //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start"); | ||
2107 | lock (OdeLock) | ||
2108 | { | ||
2109 | //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock"); | ||
2110 | RemoveAllJointsConnectedToActor(actor); | ||
2111 | } | ||
2112 | } | ||
2113 | |||
2114 | // normally called from within OnJointMoved, which is called from within a lock (OdeLock) | ||
2115 | public override Vector3 GetJointAnchor(PhysicsJoint joint) | ||
2116 | { | ||
2117 | Debug.Assert(joint.IsInPhysicsEngine); | ||
2118 | d.Vector3 pos = new d.Vector3(); | ||
2119 | |||
2120 | if (!(joint is OdePhysicsJoint)) | ||
2121 | { | ||
2122 | DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); | ||
2123 | } | ||
2124 | else | ||
2125 | { | ||
2126 | OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; | ||
2127 | switch (odeJoint.Type) | ||
2128 | { | ||
2129 | case PhysicsJointType.Ball: | ||
2130 | d.JointGetBallAnchor(odeJoint.jointID, out pos); | ||
2131 | break; | ||
2132 | case PhysicsJointType.Hinge: | ||
2133 | d.JointGetHingeAnchor(odeJoint.jointID, out pos); | ||
2134 | break; | ||
2135 | } | ||
2136 | } | ||
2137 | return new Vector3(pos.X, pos.Y, pos.Z); | ||
2138 | } | ||
2139 | |||
2140 | /// <summary> | ||
2141 | /// Get joint axis. | ||
2142 | /// </summary> | ||
2143 | /// <remarks> | ||
2144 | /// normally called from within OnJointMoved, which is called from within a lock (OdeLock) | ||
2145 | /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function | ||
2146 | /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by | ||
2147 | /// keeping track of the joint's original orientation relative to one of the involved bodies. | ||
2148 | /// </remarks> | ||
2149 | /// <param name="joint"></param> | ||
2150 | /// <returns></returns> | ||
2151 | public override Vector3 GetJointAxis(PhysicsJoint joint) | ||
2152 | { | ||
2153 | Debug.Assert(joint.IsInPhysicsEngine); | ||
2154 | d.Vector3 axis = new d.Vector3(); | ||
2155 | |||
2156 | if (!(joint is OdePhysicsJoint)) | ||
2157 | { | ||
2158 | DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); | ||
2159 | } | ||
2160 | else | ||
2161 | { | ||
2162 | OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; | ||
2163 | switch (odeJoint.Type) | ||
2164 | { | ||
2165 | case PhysicsJointType.Ball: | ||
2166 | DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene); | ||
2167 | break; | ||
2168 | case PhysicsJointType.Hinge: | ||
2169 | d.JointGetHingeAxis(odeJoint.jointID, out axis); | ||
2170 | break; | ||
2171 | } | ||
2172 | } | ||
2173 | return new Vector3(axis.X, axis.Y, axis.Z); | ||
2174 | } | ||
2175 | |||
2176 | /// <summary> | ||
2177 | /// Stop this prim being subject to physics | ||
2178 | /// </summary> | ||
2179 | /// <param name="prim"></param> | ||
2180 | internal void DeactivatePrim(OdePrim prim) | ||
2181 | { | ||
2182 | _activeprims.Remove(prim); | ||
2183 | } | ||
2184 | |||
2185 | public override void RemovePrim(PhysicsActor prim) | ||
2186 | { | ||
2187 | // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be | ||
2188 | // removed in the next physics simulate pass. | ||
2189 | if (prim is OdePrim) | ||
2190 | { | ||
2191 | lock (OdeLock) | ||
2192 | { | ||
2193 | OdePrim p = (OdePrim) prim; | ||
2194 | |||
2195 | p.setPrimForRemoval(); | ||
2196 | AddPhysicsActorTaint(prim); | ||
2197 | } | ||
2198 | } | ||
2199 | } | ||
2200 | |||
2201 | /// <summary> | ||
2202 | /// This is called from within simulate but outside the locked portion | ||
2203 | /// We need to do our own locking here | ||
2204 | /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in | ||
2205 | /// Simulate() -- justincc). | ||
2206 | /// | ||
2207 | /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. | ||
2208 | /// | ||
2209 | /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory | ||
2210 | /// that the space was using. | ||
2211 | /// </summary> | ||
2212 | /// <param name="prim"></param> | ||
2213 | internal void RemovePrimThreadLocked(OdePrim prim) | ||
2214 | { | ||
2215 | // m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID); | ||
2216 | |||
2217 | lock (prim) | ||
2218 | { | ||
2219 | RemoveCollisionEventReporting(prim); | ||
2220 | |||
2221 | if (prim.prim_geom != IntPtr.Zero) | ||
2222 | { | ||
2223 | prim.ResetTaints(); | ||
2224 | |||
2225 | if (prim.IsPhysical) | ||
2226 | { | ||
2227 | prim.disableBody(); | ||
2228 | if (prim.childPrim) | ||
2229 | { | ||
2230 | prim.childPrim = false; | ||
2231 | prim.Body = IntPtr.Zero; | ||
2232 | prim.m_disabled = true; | ||
2233 | prim.IsPhysical = false; | ||
2234 | } | ||
2235 | |||
2236 | |||
2237 | } | ||
2238 | prim.m_targetSpace = IntPtr.Zero; | ||
2239 | if (!prim.RemoveGeom()) | ||
2240 | m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene"); | ||
2241 | |||
2242 | lock (_prims) | ||
2243 | _prims.Remove(prim); | ||
2244 | |||
2245 | |||
2246 | if (SupportsNINJAJoints) | ||
2247 | RemoveAllJointsConnectedToActorThreadLocked(prim); | ||
2248 | } | ||
2249 | } | ||
2250 | } | ||
2251 | |||
2252 | #endregion | ||
2253 | |||
2254 | #region Space Separation Calculation | ||
2255 | |||
2256 | /// <summary> | ||
2257 | /// Takes a space pointer and zeros out the array we're using to hold the spaces | ||
2258 | /// </summary> | ||
2259 | /// <param name="pSpace"></param> | ||
2260 | private void resetSpaceArrayItemToZero(IntPtr pSpace) | ||
2261 | { | ||
2262 | for (int x = 0; x < staticPrimspace.GetLength(0); x++) | ||
2263 | { | ||
2264 | for (int y = 0; y < staticPrimspace.GetLength(1); y++) | ||
2265 | { | ||
2266 | if (staticPrimspace[x, y] == pSpace) | ||
2267 | staticPrimspace[x, y] = IntPtr.Zero; | ||
2268 | } | ||
2269 | } | ||
2270 | } | ||
2271 | |||
2272 | // private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY) | ||
2273 | // { | ||
2274 | // staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; | ||
2275 | // } | ||
2276 | |||
2277 | /// <summary> | ||
2278 | /// Called when a static prim moves. Allocates a space for the prim based on its position | ||
2279 | /// </summary> | ||
2280 | /// <param name="geom">the pointer to the geom that moved</param> | ||
2281 | /// <param name="pos">the position that the geom moved to</param> | ||
2282 | /// <param name="currentspace">a pointer to the space it was in before it was moved.</param> | ||
2283 | /// <returns>a pointer to the new space it's in</returns> | ||
2284 | internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace) | ||
2285 | { | ||
2286 | // Called from setting the Position and Size of an ODEPrim so | ||
2287 | // it's already in locked space. | ||
2288 | |||
2289 | // we don't want to remove the main space | ||
2290 | // we don't need to test physical here because this function should | ||
2291 | // never be called if the prim is physical(active) | ||
2292 | |||
2293 | // All physical prim end up in the root space | ||
2294 | //Thread.Sleep(20); | ||
2295 | if (currentspace != space) | ||
2296 | { | ||
2297 | //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString()); | ||
2298 | //if (currentspace == IntPtr.Zero) | ||
2299 | //{ | ||
2300 | //int adfadf = 0; | ||
2301 | //} | ||
2302 | if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero) | ||
2303 | { | ||
2304 | if (d.GeomIsSpace(currentspace)) | ||
2305 | { | ||
2306 | // waitForSpaceUnlock(currentspace); | ||
2307 | d.SpaceRemove(currentspace, geom); | ||
2308 | } | ||
2309 | else | ||
2310 | { | ||
2311 | m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + | ||
2312 | " Geom:" + geom); | ||
2313 | } | ||
2314 | } | ||
2315 | else | ||
2316 | { | ||
2317 | IntPtr sGeomIsIn = d.GeomGetSpace(geom); | ||
2318 | if (sGeomIsIn != IntPtr.Zero) | ||
2319 | { | ||
2320 | if (d.GeomIsSpace(currentspace)) | ||
2321 | { | ||
2322 | // waitForSpaceUnlock(sGeomIsIn); | ||
2323 | d.SpaceRemove(sGeomIsIn, geom); | ||
2324 | } | ||
2325 | else | ||
2326 | { | ||
2327 | m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + | ||
2328 | sGeomIsIn + " Geom:" + geom); | ||
2329 | } | ||
2330 | } | ||
2331 | } | ||
2332 | |||
2333 | //If there are no more geometries in the sub-space, we don't need it in the main space anymore | ||
2334 | if (d.SpaceGetNumGeoms(currentspace) == 0) | ||
2335 | { | ||
2336 | if (currentspace != IntPtr.Zero) | ||
2337 | { | ||
2338 | if (d.GeomIsSpace(currentspace)) | ||
2339 | { | ||
2340 | d.SpaceRemove(space, currentspace); | ||
2341 | // free up memory used by the space. | ||
2342 | |||
2343 | resetSpaceArrayItemToZero(currentspace); | ||
2344 | } | ||
2345 | else | ||
2346 | { | ||
2347 | m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + | ||
2348 | currentspace + " Geom:" + geom); | ||
2349 | } | ||
2350 | } | ||
2351 | } | ||
2352 | } | ||
2353 | else | ||
2354 | { | ||
2355 | // this is a physical object that got disabled. ;.; | ||
2356 | if (currentspace != IntPtr.Zero && geom != IntPtr.Zero) | ||
2357 | { | ||
2358 | if (d.SpaceQuery(currentspace, geom)) | ||
2359 | { | ||
2360 | if (d.GeomIsSpace(currentspace)) | ||
2361 | { | ||
2362 | // waitForSpaceUnlock(currentspace); | ||
2363 | d.SpaceRemove(currentspace, geom); | ||
2364 | } | ||
2365 | else | ||
2366 | { | ||
2367 | m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + | ||
2368 | currentspace + " Geom:" + geom); | ||
2369 | } | ||
2370 | } | ||
2371 | else | ||
2372 | { | ||
2373 | IntPtr sGeomIsIn = d.GeomGetSpace(geom); | ||
2374 | if (sGeomIsIn != IntPtr.Zero) | ||
2375 | { | ||
2376 | if (d.GeomIsSpace(sGeomIsIn)) | ||
2377 | { | ||
2378 | // waitForSpaceUnlock(sGeomIsIn); | ||
2379 | d.SpaceRemove(sGeomIsIn, geom); | ||
2380 | } | ||
2381 | else | ||
2382 | { | ||
2383 | m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + | ||
2384 | sGeomIsIn + " Geom:" + geom); | ||
2385 | } | ||
2386 | } | ||
2387 | } | ||
2388 | } | ||
2389 | } | ||
2390 | |||
2391 | // The routines in the Position and Size sections do the 'inserting' into the space, | ||
2392 | // so all we have to do is make sure that the space that we're putting the prim into | ||
2393 | // is in the 'main' space. | ||
2394 | int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos); | ||
2395 | IntPtr newspace = calculateSpaceForGeom(pos); | ||
2396 | |||
2397 | if (newspace == IntPtr.Zero) | ||
2398 | { | ||
2399 | newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); | ||
2400 | d.HashSpaceSetLevels(newspace, HashspaceLow, HashspaceHigh); | ||
2401 | } | ||
2402 | |||
2403 | return newspace; | ||
2404 | } | ||
2405 | |||
2406 | /// <summary> | ||
2407 | /// Creates a new space at X Y | ||
2408 | /// </summary> | ||
2409 | /// <param name="iprimspaceArrItemX"></param> | ||
2410 | /// <param name="iprimspaceArrItemY"></param> | ||
2411 | /// <returns>A pointer to the created space</returns> | ||
2412 | internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY) | ||
2413 | { | ||
2414 | // creating a new space for prim and inserting it into main space. | ||
2415 | staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero); | ||
2416 | d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space); | ||
2417 | // waitForSpaceUnlock(space); | ||
2418 | d.SpaceSetSublevel(space, 1); | ||
2419 | d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]); | ||
2420 | |||
2421 | return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; | ||
2422 | } | ||
2423 | |||
2424 | /// <summary> | ||
2425 | /// Calculates the space the prim should be in by its position | ||
2426 | /// </summary> | ||
2427 | /// <param name="pos"></param> | ||
2428 | /// <returns>a pointer to the space. This could be a new space or reused space.</returns> | ||
2429 | internal IntPtr calculateSpaceForGeom(Vector3 pos) | ||
2430 | { | ||
2431 | int[] xyspace = calculateSpaceArrayItemFromPos(pos); | ||
2432 | //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString()); | ||
2433 | return staticPrimspace[xyspace[0], xyspace[1]]; | ||
2434 | } | ||
2435 | |||
2436 | /// <summary> | ||
2437 | /// Holds the space allocation logic | ||
2438 | /// </summary> | ||
2439 | /// <param name="pos"></param> | ||
2440 | /// <returns>an array item based on the position</returns> | ||
2441 | internal int[] calculateSpaceArrayItemFromPos(Vector3 pos) | ||
2442 | { | ||
2443 | int[] returnint = new int[2]; | ||
2444 | |||
2445 | returnint[0] = (int) (pos.X * spacesPerMeterX); | ||
2446 | |||
2447 | if (returnint[0] > spaceGridMaxX) | ||
2448 | returnint[0] = spaceGridMaxX; | ||
2449 | if (returnint[0] < 0) | ||
2450 | returnint[0] = 0; | ||
2451 | |||
2452 | returnint[1] = (int)(pos.Y * spacesPerMeterY); | ||
2453 | if (returnint[1] > spaceGridMaxY) | ||
2454 | returnint[1] = spaceGridMaxY; | ||
2455 | if (returnint[1] < 0) | ||
2456 | returnint[1] = 0; | ||
2457 | |||
2458 | return returnint; | ||
2459 | } | ||
2460 | |||
2461 | #endregion | ||
2462 | |||
2463 | /// <summary> | ||
2464 | /// Routine to figure out if we need to mesh this prim with our mesher | ||
2465 | /// </summary> | ||
2466 | /// <param name="pbs"></param> | ||
2467 | /// <returns></returns> | ||
2468 | internal bool needsMeshing(PrimitiveBaseShape pbs) | ||
2469 | { | ||
2470 | // most of this is redundant now as the mesher will return null if it cant mesh a prim | ||
2471 | // but we still need to check for sculptie meshing being enabled so this is the most | ||
2472 | // convenient place to do it for now... | ||
2473 | |||
2474 | // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f) | ||
2475 | // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString()); | ||
2476 | int iPropertiesNotSupportedDefault = 0; | ||
2477 | |||
2478 | if (pbs.SculptEntry && !meshSculptedPrim) | ||
2479 | { | ||
2480 | #if SPAM | ||
2481 | m_log.Warn("NonMesh"); | ||
2482 | #endif | ||
2483 | return false; | ||
2484 | } | ||
2485 | |||
2486 | // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim | ||
2487 | if (!forceSimplePrimMeshing && !pbs.SculptEntry) | ||
2488 | { | ||
2489 | if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | ||
2490 | || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 | ||
2491 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) | ||
2492 | { | ||
2493 | |||
2494 | if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
2495 | && pbs.ProfileHollow == 0 | ||
2496 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
2497 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
2498 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
2499 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
2500 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) | ||
2501 | { | ||
2502 | #if SPAM | ||
2503 | m_log.Warn("NonMesh"); | ||
2504 | #endif | ||
2505 | return false; | ||
2506 | } | ||
2507 | } | ||
2508 | } | ||
2509 | |||
2510 | if (pbs.ProfileHollow != 0) | ||
2511 | iPropertiesNotSupportedDefault++; | ||
2512 | |||
2513 | if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) | ||
2514 | iPropertiesNotSupportedDefault++; | ||
2515 | |||
2516 | if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) | ||
2517 | iPropertiesNotSupportedDefault++; | ||
2518 | |||
2519 | if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) | ||
2520 | iPropertiesNotSupportedDefault++; | ||
2521 | |||
2522 | if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) | ||
2523 | iPropertiesNotSupportedDefault++; | ||
2524 | |||
2525 | if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) | ||
2526 | iPropertiesNotSupportedDefault++; | ||
2527 | |||
2528 | if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) | ||
2529 | iPropertiesNotSupportedDefault++; | ||
2530 | |||
2531 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) | ||
2532 | iPropertiesNotSupportedDefault++; | ||
2533 | |||
2534 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) | ||
2535 | iPropertiesNotSupportedDefault++; | ||
2536 | |||
2537 | // test for torus | ||
2538 | if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) | ||
2539 | { | ||
2540 | if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
2541 | { | ||
2542 | iPropertiesNotSupportedDefault++; | ||
2543 | } | ||
2544 | } | ||
2545 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
2546 | { | ||
2547 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
2548 | { | ||
2549 | iPropertiesNotSupportedDefault++; | ||
2550 | } | ||
2551 | |||
2552 | // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits | ||
2553 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
2554 | { | ||
2555 | iPropertiesNotSupportedDefault++; | ||
2556 | } | ||
2557 | } | ||
2558 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
2559 | { | ||
2560 | if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) | ||
2561 | { | ||
2562 | iPropertiesNotSupportedDefault++; | ||
2563 | } | ||
2564 | } | ||
2565 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
2566 | { | ||
2567 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
2568 | { | ||
2569 | iPropertiesNotSupportedDefault++; | ||
2570 | } | ||
2571 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
2572 | { | ||
2573 | iPropertiesNotSupportedDefault++; | ||
2574 | } | ||
2575 | } | ||
2576 | |||
2577 | if (pbs.SculptEntry && meshSculptedPrim) | ||
2578 | iPropertiesNotSupportedDefault++; | ||
2579 | |||
2580 | if (iPropertiesNotSupportedDefault == 0) | ||
2581 | { | ||
2582 | #if SPAM | ||
2583 | m_log.Warn("NonMesh"); | ||
2584 | #endif | ||
2585 | return false; | ||
2586 | } | ||
2587 | #if SPAM | ||
2588 | m_log.Debug("Mesh"); | ||
2589 | #endif | ||
2590 | return true; | ||
2591 | } | ||
2592 | |||
2593 | /// <summary> | ||
2594 | /// Called after our prim properties are set Scale, position etc. | ||
2595 | /// </summary> | ||
2596 | /// <remarks> | ||
2597 | /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex | ||
2598 | /// This assures us that we have no race conditions | ||
2599 | /// </remarks> | ||
2600 | /// <param name="actor"></param> | ||
2601 | public override void AddPhysicsActorTaint(PhysicsActor actor) | ||
2602 | { | ||
2603 | if (actor is OdePrim) | ||
2604 | { | ||
2605 | OdePrim taintedprim = ((OdePrim)actor); | ||
2606 | lock (_taintedPrims) | ||
2607 | _taintedPrims.Add(taintedprim); | ||
2608 | } | ||
2609 | else if (actor is OdeCharacter) | ||
2610 | { | ||
2611 | OdeCharacter taintedchar = ((OdeCharacter)actor); | ||
2612 | lock (_taintedActors) | ||
2613 | { | ||
2614 | _taintedActors.Add(taintedchar); | ||
2615 | if (taintedchar.bad) | ||
2616 | m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); | ||
2617 | } | ||
2618 | } | ||
2619 | } | ||
2620 | |||
2621 | // does all pending changes generated during region load process | ||
2622 | public override void ProcessPreSimulation() | ||
2623 | { | ||
2624 | lock (OdeLock) | ||
2625 | { | ||
2626 | if (world == IntPtr.Zero) | ||
2627 | { | ||
2628 | _taintedPrims.Clear();; | ||
2629 | return; | ||
2630 | } | ||
2631 | |||
2632 | int donechanges = 0; | ||
2633 | if (_taintedPrims.Count > 0) | ||
2634 | { | ||
2635 | |||
2636 | m_log.InfoFormat("[Ode] start processing pending actor operations"); | ||
2637 | int tstart = Util.EnvironmentTickCount(); | ||
2638 | |||
2639 | d.AllocateODEDataForThread(0); | ||
2640 | |||
2641 | lock (_taintedPrims) | ||
2642 | { | ||
2643 | foreach (OdePrim prim in _taintedPrims) | ||
2644 | { | ||
2645 | if (prim.m_taintremove) | ||
2646 | RemovePrimThreadLocked(prim); | ||
2647 | else | ||
2648 | prim.ProcessTaints(); | ||
2649 | |||
2650 | prim.m_collisionscore = 0; | ||
2651 | donechanges++; | ||
2652 | } | ||
2653 | _taintedPrims.Clear(); | ||
2654 | } | ||
2655 | |||
2656 | int time = Util.EnvironmentTickCountSubtract(tstart); | ||
2657 | m_log.InfoFormat("[Ode] finished {0} operations in {1}ms", donechanges, time); | ||
2658 | } | ||
2659 | m_log.InfoFormat("[Ode] {0} prim actors loaded",_prims.Count); | ||
2660 | } | ||
2661 | } | ||
2662 | |||
2663 | |||
2664 | /// <summary> | ||
2665 | /// This is our main simulate loop | ||
2666 | /// </summary> | ||
2667 | /// <remarks> | ||
2668 | /// It's thread locked by a Mutex in the scene. | ||
2669 | /// It holds Collisions, it instructs ODE to step through the physical reactions | ||
2670 | /// It moves the objects around in memory | ||
2671 | /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) | ||
2672 | /// </remarks> | ||
2673 | /// <param name="timeStep"></param> | ||
2674 | /// <returns>The number of frames simulated over that period.</returns> | ||
2675 | public override float Simulate(float timeStep) | ||
2676 | { | ||
2677 | if (!_worldInitialized) | ||
2678 | return 1.0f; | ||
2679 | |||
2680 | int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; | ||
2681 | int tempTick = 0, tempTick2 = 0; | ||
2682 | |||
2683 | if (framecount >= int.MaxValue) | ||
2684 | framecount = 0; | ||
2685 | |||
2686 | framecount++; | ||
2687 | |||
2688 | float fps = 0; | ||
2689 | |||
2690 | step_time += timeStep; | ||
2691 | |||
2692 | float HalfOdeStep = ODE_STEPSIZE * 0.5f; | ||
2693 | if (step_time < HalfOdeStep) | ||
2694 | return 0; | ||
2695 | |||
2696 | |||
2697 | // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential | ||
2698 | // deadlock if the collision event tries to lock something else later on which is already locked by a | ||
2699 | // caller that is adding or removing the collision event. | ||
2700 | lock (m_collisionEventActorsChanges) | ||
2701 | { | ||
2702 | foreach (KeyValuePair<uint, PhysicsActor> kvp in m_collisionEventActorsChanges) | ||
2703 | { | ||
2704 | if (kvp.Value == null) | ||
2705 | m_collisionEventActors.Remove(kvp.Key); | ||
2706 | else | ||
2707 | m_collisionEventActors[kvp.Key] = kvp.Value; | ||
2708 | } | ||
2709 | |||
2710 | m_collisionEventActorsChanges.Clear(); | ||
2711 | } | ||
2712 | |||
2713 | if (SupportsNINJAJoints) | ||
2714 | { | ||
2715 | DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks | ||
2716 | CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks | ||
2717 | } | ||
2718 | |||
2719 | |||
2720 | lock (OdeLock) | ||
2721 | { | ||
2722 | d.AllocateODEDataForThread(~0U); | ||
2723 | |||
2724 | while (step_time > HalfOdeStep) | ||
2725 | { | ||
2726 | try | ||
2727 | { | ||
2728 | if (CollectStats) | ||
2729 | tempTick = Util.EnvironmentTickCount(); | ||
2730 | |||
2731 | lock (_taintedActors) | ||
2732 | { | ||
2733 | foreach (OdeCharacter character in _taintedActors) | ||
2734 | character.ProcessTaints(); | ||
2735 | |||
2736 | _taintedActors.Clear(); | ||
2737 | } | ||
2738 | |||
2739 | if (CollectStats) | ||
2740 | { | ||
2741 | tempTick2 = Util.EnvironmentTickCount(); | ||
2742 | m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); | ||
2743 | tempTick = tempTick2; | ||
2744 | } | ||
2745 | |||
2746 | lock (_taintedPrims) | ||
2747 | { | ||
2748 | foreach (OdePrim prim in _taintedPrims) | ||
2749 | { | ||
2750 | if (prim.m_taintremove) | ||
2751 | { | ||
2752 | // Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name); | ||
2753 | RemovePrimThreadLocked(prim); | ||
2754 | } | ||
2755 | else | ||
2756 | { | ||
2757 | // Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name); | ||
2758 | prim.ProcessTaints(); | ||
2759 | } | ||
2760 | |||
2761 | prim.m_collisionscore = 0; | ||
2762 | |||
2763 | // This loop can block up the Heartbeat for a very long time on large regions. | ||
2764 | // We need to let the Watchdog know that the Heartbeat is not dead | ||
2765 | // NOTE: This is currently commented out, but if things like OAR loading are | ||
2766 | // timing the heartbeat out we will need to uncomment it | ||
2767 | //Watchdog.UpdateThread(); | ||
2768 | } | ||
2769 | |||
2770 | if (SupportsNINJAJoints) | ||
2771 | SimulatePendingNINJAJoints(); | ||
2772 | |||
2773 | _taintedPrims.Clear(); | ||
2774 | } | ||
2775 | |||
2776 | if (CollectStats) | ||
2777 | { | ||
2778 | tempTick2 = Util.EnvironmentTickCount(); | ||
2779 | m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); | ||
2780 | tempTick = tempTick2; | ||
2781 | } | ||
2782 | |||
2783 | // Move characters | ||
2784 | foreach (OdeCharacter actor in _characters) | ||
2785 | actor.Move(defects); | ||
2786 | |||
2787 | if (defects.Count != 0) | ||
2788 | { | ||
2789 | foreach (OdeCharacter actor in defects) | ||
2790 | { | ||
2791 | m_log.ErrorFormat( | ||
2792 | "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving", | ||
2793 | actor.Name, actor.LocalID, PhysicsSceneName); | ||
2794 | |||
2795 | RemoveCharacter(actor); | ||
2796 | actor.DestroyOdeStructures(); | ||
2797 | } | ||
2798 | |||
2799 | defects.Clear(); | ||
2800 | } | ||
2801 | |||
2802 | if (CollectStats) | ||
2803 | { | ||
2804 | tempTick2 = Util.EnvironmentTickCount(); | ||
2805 | m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); | ||
2806 | tempTick = tempTick2; | ||
2807 | } | ||
2808 | |||
2809 | // Move other active objects | ||
2810 | foreach (OdePrim prim in _activeprims) | ||
2811 | { | ||
2812 | prim.m_collisionscore = 0; | ||
2813 | prim.Move(timeStep); | ||
2814 | } | ||
2815 | |||
2816 | if (CollectStats) | ||
2817 | { | ||
2818 | tempTick2 = Util.EnvironmentTickCount(); | ||
2819 | m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); | ||
2820 | tempTick = tempTick2; | ||
2821 | } | ||
2822 | |||
2823 | m_rayCastManager.ProcessQueuedRequests(); | ||
2824 | |||
2825 | if (CollectStats) | ||
2826 | { | ||
2827 | tempTick2 = Util.EnvironmentTickCount(); | ||
2828 | m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); | ||
2829 | tempTick = tempTick2; | ||
2830 | } | ||
2831 | |||
2832 | collision_optimized(); | ||
2833 | |||
2834 | if (CollectStats) | ||
2835 | { | ||
2836 | tempTick2 = Util.EnvironmentTickCount(); | ||
2837 | m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); | ||
2838 | tempTick = tempTick2; | ||
2839 | } | ||
2840 | |||
2841 | foreach (PhysicsActor obj in m_collisionEventActors.Values) | ||
2842 | { | ||
2843 | // m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID); | ||
2844 | |||
2845 | switch ((ActorTypes)obj.PhysicsActorType) | ||
2846 | { | ||
2847 | case ActorTypes.Agent: | ||
2848 | OdeCharacter cobj = (OdeCharacter)obj; | ||
2849 | cobj.AddCollisionFrameTime(100); | ||
2850 | cobj.SendCollisions(); | ||
2851 | break; | ||
2852 | |||
2853 | case ActorTypes.Prim: | ||
2854 | OdePrim pobj = (OdePrim)obj; | ||
2855 | pobj.SendCollisions(); | ||
2856 | break; | ||
2857 | } | ||
2858 | } | ||
2859 | |||
2860 | // if (m_global_contactcount > 0) | ||
2861 | // m_log.DebugFormat( | ||
2862 | // "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount); | ||
2863 | |||
2864 | m_global_contactcount = 0; | ||
2865 | |||
2866 | if (CollectStats) | ||
2867 | { | ||
2868 | tempTick2 = Util.EnvironmentTickCount(); | ||
2869 | m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); | ||
2870 | tempTick = tempTick2; | ||
2871 | } | ||
2872 | |||
2873 | lock(SimulationLock) | ||
2874 | d.WorldQuickStep(world, ODE_STEPSIZE); | ||
2875 | |||
2876 | if (CollectStats) | ||
2877 | m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); | ||
2878 | |||
2879 | d.JointGroupEmpty(contactgroup); | ||
2880 | } | ||
2881 | catch (Exception e) | ||
2882 | { | ||
2883 | m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e); | ||
2884 | } | ||
2885 | |||
2886 | step_time -= ODE_STEPSIZE; | ||
2887 | fps += ODE_STEPSIZE; | ||
2888 | } | ||
2889 | |||
2890 | if (CollectStats) | ||
2891 | tempTick = Util.EnvironmentTickCount(); | ||
2892 | |||
2893 | foreach (OdeCharacter actor in _characters) | ||
2894 | { | ||
2895 | if (actor.bad) | ||
2896 | m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); | ||
2897 | |||
2898 | actor.UpdatePositionAndVelocity(defects); | ||
2899 | } | ||
2900 | |||
2901 | if (defects.Count != 0) | ||
2902 | { | ||
2903 | foreach (OdeCharacter actor in defects) | ||
2904 | { | ||
2905 | m_log.ErrorFormat( | ||
2906 | "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity", | ||
2907 | actor.Name, actor.LocalID, PhysicsSceneName); | ||
2908 | |||
2909 | RemoveCharacter(actor); | ||
2910 | actor.DestroyOdeStructures(); | ||
2911 | } | ||
2912 | |||
2913 | defects.Clear(); | ||
2914 | } | ||
2915 | |||
2916 | if (CollectStats) | ||
2917 | { | ||
2918 | tempTick2 = Util.EnvironmentTickCount(); | ||
2919 | m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); | ||
2920 | tempTick = tempTick2; | ||
2921 | } | ||
2922 | |||
2923 | //if (timeStep < 0.2f) | ||
2924 | |||
2925 | foreach (OdePrim prim in _activeprims) | ||
2926 | { | ||
2927 | if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) | ||
2928 | { | ||
2929 | prim.UpdatePositionAndVelocity(); | ||
2930 | |||
2931 | if (SupportsNINJAJoints) | ||
2932 | SimulateActorPendingJoints(prim); | ||
2933 | } | ||
2934 | } | ||
2935 | |||
2936 | if (CollectStats) | ||
2937 | m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); | ||
2938 | |||
2939 | //DumpJointInfo(); | ||
2940 | |||
2941 | // Finished with all sim stepping. If requested, dump world state to file for debugging. | ||
2942 | // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? | ||
2943 | // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? | ||
2944 | if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0)) | ||
2945 | { | ||
2946 | string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename | ||
2947 | string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file | ||
2948 | |||
2949 | if (physics_logging_append_existing_logfile) | ||
2950 | { | ||
2951 | string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------"; | ||
2952 | TextWriter fwriter = File.AppendText(fname); | ||
2953 | fwriter.WriteLine(header); | ||
2954 | fwriter.Close(); | ||
2955 | } | ||
2956 | |||
2957 | d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); | ||
2958 | } | ||
2959 | |||
2960 | latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun); | ||
2961 | |||
2962 | // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics | ||
2963 | // has a max of 100 ms to run theoretically. | ||
2964 | // If the main loop stalls, it calls Simulate later which makes the tick count ms larger. | ||
2965 | // If Physics stalls, it takes longer which makes the tick count ms larger. | ||
2966 | |||
2967 | if (latertickcount < 100) | ||
2968 | { | ||
2969 | m_timeDilation = 1.0f; | ||
2970 | } | ||
2971 | else | ||
2972 | { | ||
2973 | m_timeDilation = 100f / latertickcount; | ||
2974 | //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f); | ||
2975 | } | ||
2976 | |||
2977 | tickCountFrameRun = Util.EnvironmentTickCount(); | ||
2978 | |||
2979 | if (CollectStats) | ||
2980 | m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick); | ||
2981 | } | ||
2982 | |||
2983 | fps *= 1.0f/timeStep; | ||
2984 | return fps; | ||
2985 | } | ||
2986 | |||
2987 | /// <summary> | ||
2988 | /// Simulate pending NINJA joints. | ||
2989 | /// </summary> | ||
2990 | /// <remarks> | ||
2991 | /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else. | ||
2992 | /// </remarks> | ||
2993 | private void SimulatePendingNINJAJoints() | ||
2994 | { | ||
2995 | // Create pending joints, if possible | ||
2996 | |||
2997 | // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating | ||
2998 | // a joint requires specifying the body id of both involved bodies | ||
2999 | if (pendingJoints.Count > 0) | ||
3000 | { | ||
3001 | List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>(); | ||
3002 | //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); | ||
3003 | foreach (PhysicsJoint joint in pendingJoints) | ||
3004 | { | ||
3005 | //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); | ||
3006 | string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); | ||
3007 | List<IntPtr> jointBodies = new List<IntPtr>(); | ||
3008 | bool allJointBodiesAreReady = true; | ||
3009 | foreach (string jointParam in jointParams) | ||
3010 | { | ||
3011 | if (jointParam == "NULL") | ||
3012 | { | ||
3013 | //DoJointErrorMessage(joint, "attaching NULL joint to world"); | ||
3014 | jointBodies.Add(IntPtr.Zero); | ||
3015 | } | ||
3016 | else | ||
3017 | { | ||
3018 | //DoJointErrorMessage(joint, "looking for prim name: " + jointParam); | ||
3019 | bool foundPrim = false; | ||
3020 | lock (_prims) | ||
3021 | { | ||
3022 | foreach (OdePrim prim in _prims) // FIXME: inefficient | ||
3023 | { | ||
3024 | if (prim.SOPName == jointParam) | ||
3025 | { | ||
3026 | //DoJointErrorMessage(joint, "found for prim name: " + jointParam); | ||
3027 | if (prim.IsPhysical && prim.Body != IntPtr.Zero) | ||
3028 | { | ||
3029 | jointBodies.Add(prim.Body); | ||
3030 | foundPrim = true; | ||
3031 | break; | ||
3032 | } | ||
3033 | else | ||
3034 | { | ||
3035 | DoJointErrorMessage(joint, "prim name " + jointParam + | ||
3036 | " exists but is not (yet) physical; deferring joint creation. " + | ||
3037 | "IsPhysical property is " + prim.IsPhysical + | ||
3038 | " and body is " + prim.Body); | ||
3039 | foundPrim = false; | ||
3040 | break; | ||
3041 | } | ||
3042 | } | ||
3043 | } | ||
3044 | } | ||
3045 | if (foundPrim) | ||
3046 | { | ||
3047 | // all is fine | ||
3048 | } | ||
3049 | else | ||
3050 | { | ||
3051 | allJointBodiesAreReady = false; | ||
3052 | break; | ||
3053 | } | ||
3054 | } | ||
3055 | } | ||
3056 | |||
3057 | if (allJointBodiesAreReady) | ||
3058 | { | ||
3059 | //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); | ||
3060 | if (jointBodies[0] == jointBodies[1]) | ||
3061 | { | ||
3062 | DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); | ||
3063 | } | ||
3064 | else | ||
3065 | { | ||
3066 | switch (joint.Type) | ||
3067 | { | ||
3068 | case PhysicsJointType.Ball: | ||
3069 | { | ||
3070 | IntPtr odeJoint; | ||
3071 | //DoJointErrorMessage(joint, "ODE creating ball joint "); | ||
3072 | odeJoint = d.JointCreateBall(world, IntPtr.Zero); | ||
3073 | //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); | ||
3074 | d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); | ||
3075 | //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position); | ||
3076 | d.JointSetBallAnchor(odeJoint, | ||
3077 | joint.Position.X, | ||
3078 | joint.Position.Y, | ||
3079 | joint.Position.Z); | ||
3080 | //DoJointErrorMessage(joint, "ODE joint setting OK"); | ||
3081 | //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: "); | ||
3082 | //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment")); | ||
3083 | //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: "); | ||
3084 | //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment")); | ||
3085 | |||
3086 | if (joint is OdePhysicsJoint) | ||
3087 | { | ||
3088 | ((OdePhysicsJoint)joint).jointID = odeJoint; | ||
3089 | } | ||
3090 | else | ||
3091 | { | ||
3092 | DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); | ||
3093 | } | ||
3094 | } | ||
3095 | break; | ||
3096 | case PhysicsJointType.Hinge: | ||
3097 | { | ||
3098 | IntPtr odeJoint; | ||
3099 | //DoJointErrorMessage(joint, "ODE creating hinge joint "); | ||
3100 | odeJoint = d.JointCreateHinge(world, IntPtr.Zero); | ||
3101 | //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); | ||
3102 | d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); | ||
3103 | //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position); | ||
3104 | d.JointSetHingeAnchor(odeJoint, | ||
3105 | joint.Position.X, | ||
3106 | joint.Position.Y, | ||
3107 | joint.Position.Z); | ||
3108 | // We use the orientation of the x-axis of the joint's coordinate frame | ||
3109 | // as the axis for the hinge. | ||
3110 | |||
3111 | // Therefore, we must get the joint's coordinate frame based on the | ||
3112 | // joint.Rotation field, which originates from the orientation of the | ||
3113 | // joint's proxy object in the scene. | ||
3114 | |||
3115 | // The joint's coordinate frame is defined as the transformation matrix | ||
3116 | // that converts a vector from joint-local coordinates into world coordinates. | ||
3117 | // World coordinates are defined as the XYZ coordinate system of the sim, | ||
3118 | // as shown in the top status-bar of the viewer. | ||
3119 | |||
3120 | // Once we have the joint's coordinate frame, we extract its X axis (AtAxis) | ||
3121 | // and use that as the hinge axis. | ||
3122 | |||
3123 | //joint.Rotation.Normalize(); | ||
3124 | Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation); | ||
3125 | |||
3126 | // Now extract the X axis of the joint's coordinate frame. | ||
3127 | |||
3128 | // Do not try to use proxyFrame.AtAxis or you will become mired in the | ||
3129 | // tar pit of transposed, inverted, and generally messed-up orientations. | ||
3130 | // (In other words, Matrix4.AtAxis() is borked.) | ||
3131 | // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness | ||
3132 | |||
3133 | // Instead, compute the X axis of the coordinate frame by transforming | ||
3134 | // the (1,0,0) vector. At least that works. | ||
3135 | |||
3136 | //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame); | ||
3137 | Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame); | ||
3138 | //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis); | ||
3139 | //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis); | ||
3140 | d.JointSetHingeAxis(odeJoint, | ||
3141 | jointAxis.X, | ||
3142 | jointAxis.Y, | ||
3143 | jointAxis.Z); | ||
3144 | //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f); | ||
3145 | if (joint is OdePhysicsJoint) | ||
3146 | { | ||
3147 | ((OdePhysicsJoint)joint).jointID = odeJoint; | ||
3148 | } | ||
3149 | else | ||
3150 | { | ||
3151 | DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); | ||
3152 | } | ||
3153 | } | ||
3154 | break; | ||
3155 | } | ||
3156 | successfullyProcessedPendingJoints.Add(joint); | ||
3157 | } | ||
3158 | } | ||
3159 | else | ||
3160 | { | ||
3161 | DoJointErrorMessage(joint, "joint could not yet be created; still pending"); | ||
3162 | } | ||
3163 | } | ||
3164 | |||
3165 | foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) | ||
3166 | { | ||
3167 | //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); | ||
3168 | //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); | ||
3169 | InternalRemovePendingJoint(successfullyProcessedJoint); | ||
3170 | //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); | ||
3171 | InternalAddActiveJoint(successfullyProcessedJoint); | ||
3172 | //DoJointErrorMessage(successfullyProcessedJoint, "done"); | ||
3173 | } | ||
3174 | } | ||
3175 | } | ||
3176 | |||
3177 | /// <summary> | ||
3178 | /// Simulate the joint proxies of a NINJA actor. | ||
3179 | /// </summary> | ||
3180 | /// <remarks> | ||
3181 | /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there. | ||
3182 | /// </remarks> | ||
3183 | /// <param name="actor"></param> | ||
3184 | private void SimulateActorPendingJoints(OdePrim actor) | ||
3185 | { | ||
3186 | // If an actor moved, move its joint proxy objects as well. | ||
3187 | // There seems to be an event PhysicsActor.OnPositionUpdate that could be used | ||
3188 | // for this purpose but it is never called! So we just do the joint | ||
3189 | // movement code here. | ||
3190 | |||
3191 | if (actor.SOPName != null && | ||
3192 | joints_connecting_actor.ContainsKey(actor.SOPName) && | ||
3193 | joints_connecting_actor[actor.SOPName] != null && | ||
3194 | joints_connecting_actor[actor.SOPName].Count > 0) | ||
3195 | { | ||
3196 | foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) | ||
3197 | { | ||
3198 | if (affectedJoint.IsInPhysicsEngine) | ||
3199 | { | ||
3200 | DoJointMoved(affectedJoint); | ||
3201 | } | ||
3202 | else | ||
3203 | { | ||
3204 | DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); | ||
3205 | } | ||
3206 | } | ||
3207 | } | ||
3208 | } | ||
3209 | |||
3210 | public override void GetResults() | ||
3211 | { | ||
3212 | } | ||
3213 | |||
3214 | public override bool IsThreaded | ||
3215 | { | ||
3216 | // for now we won't be multithreaded | ||
3217 | get { return false; } | ||
3218 | } | ||
3219 | |||
3220 | public override void SetTerrain(float[] heightMap) | ||
3221 | { | ||
3222 | if (m_worldOffset != Vector3.Zero && m_parentScene != null) | ||
3223 | { | ||
3224 | if (m_parentScene is OdeScene) | ||
3225 | { | ||
3226 | ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset); | ||
3227 | } | ||
3228 | } | ||
3229 | else | ||
3230 | { | ||
3231 | SetTerrain(heightMap, m_worldOffset); | ||
3232 | } | ||
3233 | } | ||
3234 | |||
3235 | private void SetTerrain(float[] heightMap, Vector3 pOffset) | ||
3236 | { | ||
3237 | int startTime = Util.EnvironmentTickCount(); | ||
3238 | m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", PhysicsSceneName, pOffset); | ||
3239 | |||
3240 | |||
3241 | float[] _heightmap; | ||
3242 | |||
3243 | // ok im lasy this are just a aliases | ||
3244 | uint regionsizeX = m_regionWidth; | ||
3245 | uint regionsizeY = m_regionHeight; | ||
3246 | |||
3247 | // map is rotated | ||
3248 | uint heightmapWidth = regionsizeY + 2; | ||
3249 | uint heightmapHeight = regionsizeX + 2; | ||
3250 | |||
3251 | uint heightmapWidthSamples = heightmapWidth + 1; | ||
3252 | uint heightmapHeightSamples = heightmapHeight + 1; | ||
3253 | |||
3254 | _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples]; | ||
3255 | |||
3256 | const float scale = 1.0f; | ||
3257 | const float offset = 0.0f; | ||
3258 | const float thickness = 10f; | ||
3259 | const int wrap = 0; | ||
3260 | |||
3261 | |||
3262 | float hfmin = float.MaxValue; | ||
3263 | float hfmax = float.MinValue; | ||
3264 | float val; | ||
3265 | uint xx; | ||
3266 | uint yy; | ||
3267 | |||
3268 | uint maxXX = regionsizeX - 1; | ||
3269 | uint maxYY = regionsizeY - 1; | ||
3270 | |||
3271 | // flipping map adding one margin all around so things don't fall in edges | ||
3272 | |||
3273 | uint xt = 0; | ||
3274 | xx = 0; | ||
3275 | |||
3276 | |||
3277 | for (uint x = 0; x < heightmapWidthSamples; x++) | ||
3278 | { | ||
3279 | if (x > 1 && xx < maxXX) | ||
3280 | xx++; | ||
3281 | yy = 0; | ||
3282 | for (uint y = 0; y < heightmapHeightSamples; y++) | ||
3283 | { | ||
3284 | if (y > 1 && y < maxYY) | ||
3285 | yy += regionsizeX; | ||
3286 | |||
3287 | val = heightMap[yy + xx]; | ||
3288 | if (val < 0.0f) | ||
3289 | val = 0.0f; | ||
3290 | _heightmap[xt + y] = val; | ||
3291 | |||
3292 | if (hfmin > val) | ||
3293 | hfmin = val; | ||
3294 | if (hfmax < val) | ||
3295 | hfmax = val; | ||
3296 | } | ||
3297 | xt += heightmapHeightSamples; | ||
3298 | } | ||
3299 | |||
3300 | lock (OdeLock) | ||
3301 | { | ||
3302 | d.AllocateODEDataForThread(~0U); | ||
3303 | |||
3304 | IntPtr GroundGeom = IntPtr.Zero; | ||
3305 | if (RegionTerrain.TryGetValue(pOffset, out GroundGeom)) | ||
3306 | { | ||
3307 | RegionTerrain.Remove(pOffset); | ||
3308 | if (GroundGeom != IntPtr.Zero) | ||
3309 | { | ||
3310 | if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) | ||
3311 | { | ||
3312 | TerrainHeightFieldHeights.Remove(GroundGeom); | ||
3313 | } | ||
3314 | d.SpaceRemove(space, GroundGeom); | ||
3315 | d.GeomDestroy(GroundGeom); | ||
3316 | } | ||
3317 | |||
3318 | } | ||
3319 | IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); | ||
3320 | d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, | ||
3321 | heightmapWidth, heightmapHeight, | ||
3322 | (int)heightmapWidthSamples, | ||
3323 | (int)heightmapHeightSamples, | ||
3324 | scale, offset, thickness, wrap); | ||
3325 | |||
3326 | d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); | ||
3327 | GroundGeom = d.CreateHeightfield(space, HeightmapData, 1); | ||
3328 | if (GroundGeom != IntPtr.Zero) | ||
3329 | { | ||
3330 | d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land)); | ||
3331 | d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space)); | ||
3332 | |||
3333 | } | ||
3334 | geom_name_map[GroundGeom] = "Terrain"; | ||
3335 | |||
3336 | d.Matrix3 R = new d.Matrix3(); | ||
3337 | |||
3338 | Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); | ||
3339 | Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); | ||
3340 | |||
3341 | q1 = q1 * q2; | ||
3342 | Vector3 v3; | ||
3343 | float angle; | ||
3344 | q1.GetAxisAngle(out v3, out angle); | ||
3345 | |||
3346 | d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); | ||
3347 | d.GeomSetRotation(GroundGeom, ref R); | ||
3348 | d.GeomSetPosition(GroundGeom, pOffset.X + regionsizeX * 0.5f, pOffset.Y + regionsizeY * 0.5f, 0.0f); | ||
3349 | IntPtr testGround = IntPtr.Zero; | ||
3350 | if (RegionTerrain.TryGetValue(pOffset, out testGround)) | ||
3351 | { | ||
3352 | RegionTerrain.Remove(pOffset); | ||
3353 | } | ||
3354 | RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); | ||
3355 | TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); | ||
3356 | } | ||
3357 | |||
3358 | m_log.DebugFormat( | ||
3359 | "[ODE SCENE]: Setting terrain for {0} took {1}ms", PhysicsSceneName, Util.EnvironmentTickCountSubtract(startTime)); | ||
3360 | } | ||
3361 | |||
3362 | public override void DeleteTerrain() | ||
3363 | { | ||
3364 | } | ||
3365 | |||
3366 | internal float GetWaterLevel() | ||
3367 | { | ||
3368 | return waterlevel; | ||
3369 | } | ||
3370 | |||
3371 | public override void SetWaterLevel(float baseheight) | ||
3372 | { | ||
3373 | waterlevel = baseheight; | ||
3374 | } | ||
3375 | |||
3376 | [HandleProcessCorruptedStateExceptions] | ||
3377 | public override void Dispose() | ||
3378 | { | ||
3379 | lock(SimulationLock) | ||
3380 | lock(OdeLock) | ||
3381 | { | ||
3382 | if(world == IntPtr.Zero) | ||
3383 | return; | ||
3384 | |||
3385 | _worldInitialized = false; | ||
3386 | |||
3387 | d.AllocateODEDataForThread(~0U); | ||
3388 | |||
3389 | if (m_rayCastManager != null) | ||
3390 | { | ||
3391 | m_rayCastManager.Dispose(); | ||
3392 | m_rayCastManager = null; | ||
3393 | } | ||
3394 | |||
3395 | lock (_prims) | ||
3396 | { | ||
3397 | foreach (OdePrim prm in _prims) | ||
3398 | { | ||
3399 | RemovePrim(prm); | ||
3400 | } | ||
3401 | } | ||
3402 | |||
3403 | //foreach (OdeCharacter act in _characters) | ||
3404 | //{ | ||
3405 | //RemoveAvatar(act); | ||
3406 | //} | ||
3407 | IntPtr GroundGeom = IntPtr.Zero; | ||
3408 | if (RegionTerrain.TryGetValue(m_worldOffset, out GroundGeom)) | ||
3409 | { | ||
3410 | RegionTerrain.Remove(m_worldOffset); | ||
3411 | if (GroundGeom != IntPtr.Zero) | ||
3412 | { | ||
3413 | if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) | ||
3414 | TerrainHeightFieldHeights.Remove(GroundGeom); | ||
3415 | d.GeomDestroy(GroundGeom); | ||
3416 | } | ||
3417 | } | ||
3418 | |||
3419 | try | ||
3420 | { | ||
3421 | d.WorldDestroy(world); | ||
3422 | world = IntPtr.Zero; | ||
3423 | } | ||
3424 | catch (AccessViolationException e) | ||
3425 | { | ||
3426 | m_log.ErrorFormat("[ODE SCENE]: exception {0}", e.Message); | ||
3427 | } | ||
3428 | } | ||
3429 | } | ||
3430 | |||
3431 | private int compareByCollisionsDesc(OdePrim A, OdePrim B) | ||
3432 | { | ||
3433 | return -A.CollisionScore.CompareTo(B.CollisionScore); | ||
3434 | } | ||
3435 | |||
3436 | public override Dictionary<uint, float> GetTopColliders() | ||
3437 | { | ||
3438 | Dictionary<uint, float> topColliders; | ||
3439 | |||
3440 | lock (_prims) | ||
3441 | { | ||
3442 | List<OdePrim> orderedPrims = new List<OdePrim>(_prims); | ||
3443 | orderedPrims.Sort(compareByCollisionsDesc); | ||
3444 | topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); | ||
3445 | |||
3446 | foreach (OdePrim p in _prims) | ||
3447 | p.CollisionScore = 0; | ||
3448 | } | ||
3449 | |||
3450 | return topColliders; | ||
3451 | } | ||
3452 | |||
3453 | public override bool SupportsRayCast() | ||
3454 | { | ||
3455 | return true; | ||
3456 | } | ||
3457 | |||
3458 | public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) | ||
3459 | { | ||
3460 | if (retMethod != null) | ||
3461 | { | ||
3462 | m_rayCastManager.QueueRequest(position, direction, length, retMethod); | ||
3463 | } | ||
3464 | } | ||
3465 | |||
3466 | public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) | ||
3467 | { | ||
3468 | if (retMethod != null) | ||
3469 | { | ||
3470 | m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); | ||
3471 | } | ||
3472 | } | ||
3473 | |||
3474 | public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) | ||
3475 | { | ||
3476 | ContactResult[] ourResults = null; | ||
3477 | RayCallback retMethod = delegate(List<ContactResult> results) | ||
3478 | { | ||
3479 | ourResults = new ContactResult[results.Count]; | ||
3480 | results.CopyTo(ourResults, 0); | ||
3481 | }; | ||
3482 | int waitTime = 0; | ||
3483 | m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); | ||
3484 | while (ourResults == null && waitTime < 1000) | ||
3485 | { | ||
3486 | Thread.Sleep(1); | ||
3487 | waitTime++; | ||
3488 | } | ||
3489 | if (ourResults == null) | ||
3490 | return new List<ContactResult> (); | ||
3491 | return new List<ContactResult>(ourResults); | ||
3492 | } | ||
3493 | |||
3494 | public override Dictionary<string, float> GetStats() | ||
3495 | { | ||
3496 | if (!CollectStats) | ||
3497 | return null; | ||
3498 | |||
3499 | Dictionary<string, float> returnStats; | ||
3500 | |||
3501 | lock (OdeLock) | ||
3502 | { | ||
3503 | returnStats = new Dictionary<string, float>(m_stats); | ||
3504 | |||
3505 | // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by | ||
3506 | // 3 from the SimStatsReporter. | ||
3507 | returnStats[ODETotalAvatarsStatName] = _characters.Count * 3; | ||
3508 | returnStats[ODETotalPrimsStatName] = _prims.Count * 3; | ||
3509 | returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3; | ||
3510 | |||
3511 | InitializeExtraStats(); | ||
3512 | } | ||
3513 | |||
3514 | returnStats[ODEOtherCollisionFrameMsStatName] | ||
3515 | = returnStats[ODEOtherCollisionFrameMsStatName] | ||
3516 | - returnStats[ODENativeSpaceCollisionFrameMsStatName] | ||
3517 | - returnStats[ODENativeGeomCollisionFrameMsStatName]; | ||
3518 | |||
3519 | return returnStats; | ||
3520 | } | ||
3521 | |||
3522 | private void InitializeExtraStats() | ||
3523 | { | ||
3524 | m_stats[ODETotalFrameMsStatName] = 0; | ||
3525 | m_stats[ODEAvatarTaintMsStatName] = 0; | ||
3526 | m_stats[ODEPrimTaintMsStatName] = 0; | ||
3527 | m_stats[ODEAvatarForcesFrameMsStatName] = 0; | ||
3528 | m_stats[ODEPrimForcesFrameMsStatName] = 0; | ||
3529 | m_stats[ODERaycastingFrameMsStatName] = 0; | ||
3530 | m_stats[ODENativeStepFrameMsStatName] = 0; | ||
3531 | m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0; | ||
3532 | m_stats[ODENativeGeomCollisionFrameMsStatName] = 0; | ||
3533 | m_stats[ODEOtherCollisionFrameMsStatName] = 0; | ||
3534 | m_stats[ODECollisionNotificationFrameMsStatName] = 0; | ||
3535 | m_stats[ODEAvatarContactsStatsName] = 0; | ||
3536 | m_stats[ODEPrimContactsStatName] = 0; | ||
3537 | m_stats[ODEAvatarUpdateFrameMsStatName] = 0; | ||
3538 | m_stats[ODEPrimUpdateFrameMsStatName] = 0; | ||
3539 | } | ||
3540 | } | ||
3541 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs b/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs new file mode 100644 index 0000000..2c134e7 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs | |||
@@ -0,0 +1,153 @@ | |||
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 Nini.Config; | ||
30 | using NUnit.Framework; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
34 | using OpenSim.Region.PhysicsModule.ODE; | ||
35 | using OpenSim.Region.Framework.Scenes; | ||
36 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Tests.Common; | ||
38 | using log4net; | ||
39 | using System.Reflection; | ||
40 | |||
41 | namespace OpenSim.Region.PhysicsModule.ODE.Tests | ||
42 | { | ||
43 | [TestFixture] | ||
44 | public class ODETestClass : OpenSimTestCase | ||
45 | { | ||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | //private OpenSim.Region.PhysicsModule.ODE.OdePlugin cbt; | ||
49 | private PhysicsScene pScene; | ||
50 | private OpenSim.Region.PhysicsModule.ODE.OdeModule odemodule; | ||
51 | |||
52 | |||
53 | [SetUp] | ||
54 | public void Initialize() | ||
55 | { | ||
56 | IConfigSource openSimINI = new IniConfigSource(); | ||
57 | IConfig startupConfig = openSimINI.AddConfig("Startup"); | ||
58 | startupConfig.Set("physics", "OpenDynamicsEngine"); | ||
59 | startupConfig.Set("DecodedSculptMapPath", "j2kDecodeCache"); | ||
60 | |||
61 | Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
62 | |||
63 | //PhysicsScene pScene = physicsPluginManager.GetPhysicsScene( | ||
64 | // "BulletSim", "Meshmerizer", openSimINI, "BSTestRegion", regionExtent); | ||
65 | RegionInfo info = new RegionInfo(); | ||
66 | info.RegionName = "ODETestRegion"; | ||
67 | info.RegionSizeX = info.RegionSizeY = info.RegionSizeZ = Constants.RegionSize; | ||
68 | OpenSim.Region.Framework.Scenes.Scene scene = new OpenSim.Region.Framework.Scenes.Scene(info); | ||
69 | |||
70 | //IMesher mesher = new OpenSim.Region.PhysicsModule.Meshing.Meshmerizer(); | ||
71 | //INonSharedRegionModule mod = mesher as INonSharedRegionModule; | ||
72 | //mod.Initialise(openSimINI); | ||
73 | //mod.AddRegion(scene); | ||
74 | //mod.RegionLoaded(scene); | ||
75 | |||
76 | // pScene = new OdeScene(); | ||
77 | odemodule = new OpenSim.Region.PhysicsModule.ODE.OdeModule(); | ||
78 | Console.WriteLine("HERE " + (odemodule == null ? "Null" : "Not null")); | ||
79 | odemodule.Initialise(openSimINI); | ||
80 | odemodule.AddRegion(scene); | ||
81 | odemodule.RegionLoaded(scene); | ||
82 | |||
83 | // Loading ODEPlugin | ||
84 | //cbt = new OdePlugin(); | ||
85 | // Getting Physics Scene | ||
86 | //ps = cbt.GetScene("test"); | ||
87 | // Initializing Physics Scene. | ||
88 | //ps.Initialise(imp.GetMesher(TopConfig), null, Vector3.Zero); | ||
89 | float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize]; | ||
90 | for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++) | ||
91 | { | ||
92 | _heightmap[i] = 21f; | ||
93 | } | ||
94 | pScene = scene.PhysicsScene; | ||
95 | pScene.SetTerrain(_heightmap); | ||
96 | } | ||
97 | |||
98 | [TearDown] | ||
99 | public void Terminate() | ||
100 | { | ||
101 | pScene.DeleteTerrain(); | ||
102 | pScene.Dispose(); | ||
103 | |||
104 | } | ||
105 | |||
106 | [Test] | ||
107 | public void CreateAndDropPhysicalCube() | ||
108 | { | ||
109 | PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox(); | ||
110 | Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f); | ||
111 | Vector3 size = new Vector3(0.5f, 0.5f, 0.5f); | ||
112 | Quaternion rot = Quaternion.Identity; | ||
113 | PhysicsActor prim = pScene.AddPrimShape("CoolShape", newcube, position, size, rot, true, 0); | ||
114 | OdePrim oprim = (OdePrim)prim; | ||
115 | OdeScene pscene = (OdeScene)pScene; | ||
116 | |||
117 | Assert.That(oprim.m_taintadd); | ||
118 | |||
119 | prim.LocalID = 5; | ||
120 | |||
121 | for (int i = 0; i < 58; i++) | ||
122 | { | ||
123 | pScene.Simulate(0.133f); | ||
124 | |||
125 | Assert.That(oprim.prim_geom != (IntPtr)0); | ||
126 | |||
127 | Assert.That(oprim.m_targetSpace != (IntPtr)0); | ||
128 | |||
129 | //Assert.That(oprim.m_targetSpace == pscene.space); | ||
130 | m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space); | ||
131 | |||
132 | Assert.That(!oprim.m_taintadd); | ||
133 | m_log.Info("Prim Position (" + oprim.LocalID + "): " + prim.Position); | ||
134 | |||
135 | // Make sure we're above the ground | ||
136 | //Assert.That(prim.Position.Z > 20f); | ||
137 | //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore); | ||
138 | |||
139 | // Make sure we've got a Body | ||
140 | Assert.That(oprim.Body != (IntPtr)0); | ||
141 | //m_log.Info( | ||
142 | } | ||
143 | |||
144 | // Make sure we're not somewhere above the ground | ||
145 | Assert.That(prim.Position.Z < 21.5f); | ||
146 | |||
147 | pScene.RemovePrim(prim); | ||
148 | Assert.That(oprim.m_taintremove); | ||
149 | pScene.Simulate(0.133f); | ||
150 | Assert.That(oprim.Body == (IntPtr)0); | ||
151 | } | ||
152 | } | ||
153 | } | ||