diff options
author | Diva Canto | 2015-08-30 20:06:53 -0700 |
---|---|---|
committer | Diva Canto | 2015-08-30 20:06:53 -0700 |
commit | 1d6b33bc2da3b312cff1d1802a73aacdf72b0385 (patch) | |
tree | 393736b501aac3b31eb0810bb72d926c7f14fbf8 /OpenSim/Region/PhysicsModules/BulletS | |
parent | Moved instantiation of SceneCommunicationService object to inside the scene c... (diff) | |
download | opensim-SC_OLD-1d6b33bc2da3b312cff1d1802a73aacdf72b0385.zip opensim-SC_OLD-1d6b33bc2da3b312cff1d1802a73aacdf72b0385.tar.gz opensim-SC_OLD-1d6b33bc2da3b312cff1d1802a73aacdf72b0385.tar.bz2 opensim-SC_OLD-1d6b33bc2da3b312cff1d1802a73aacdf72b0385.tar.xz |
Major renaming of Physics dlls / folders. No functional changes, just renames.
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS')
43 files changed, 22468 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs new file mode 100755 index 0000000..3bd81d4 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs | |||
@@ -0,0 +1,2120 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using System.Runtime.InteropServices; | ||
31 | using System.Security; | ||
32 | using System.Text; | ||
33 | |||
34 | using OpenSim.Framework; | ||
35 | |||
36 | using OpenMetaverse; | ||
37 | |||
38 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
39 | { | ||
40 | public sealed class BSAPIUnman : BSAPITemplate | ||
41 | { | ||
42 | |||
43 | private sealed class BulletWorldUnman : BulletWorld | ||
44 | { | ||
45 | public IntPtr ptr; | ||
46 | public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx) | ||
47 | : base(id, physScene) | ||
48 | { | ||
49 | ptr = xx; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | private sealed class BulletBodyUnman : BulletBody | ||
54 | { | ||
55 | public IntPtr ptr; | ||
56 | public BulletBodyUnman(uint id, IntPtr xx) | ||
57 | : base(id) | ||
58 | { | ||
59 | ptr = xx; | ||
60 | } | ||
61 | public override bool HasPhysicalBody | ||
62 | { | ||
63 | get { return ptr != IntPtr.Zero; } | ||
64 | } | ||
65 | public override void Clear() | ||
66 | { | ||
67 | ptr = IntPtr.Zero; | ||
68 | } | ||
69 | public override string AddrString | ||
70 | { | ||
71 | get { return ptr.ToString("X"); } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | private sealed class BulletShapeUnman : BulletShape | ||
76 | { | ||
77 | public IntPtr ptr; | ||
78 | public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) | ||
79 | : base() | ||
80 | { | ||
81 | ptr = xx; | ||
82 | shapeType = typ; | ||
83 | } | ||
84 | public override bool HasPhysicalShape | ||
85 | { | ||
86 | get { return ptr != IntPtr.Zero; } | ||
87 | } | ||
88 | public override void Clear() | ||
89 | { | ||
90 | ptr = IntPtr.Zero; | ||
91 | } | ||
92 | public override BulletShape Clone() | ||
93 | { | ||
94 | return new BulletShapeUnman(ptr, shapeType); | ||
95 | } | ||
96 | public override bool ReferenceSame(BulletShape other) | ||
97 | { | ||
98 | BulletShapeUnman otheru = other as BulletShapeUnman; | ||
99 | return (otheru != null) && (this.ptr == otheru.ptr); | ||
100 | |||
101 | } | ||
102 | public override string AddrString | ||
103 | { | ||
104 | get { return ptr.ToString("X"); } | ||
105 | } | ||
106 | } | ||
107 | private sealed class BulletConstraintUnman : BulletConstraint | ||
108 | { | ||
109 | public BulletConstraintUnman(IntPtr xx) : base() | ||
110 | { | ||
111 | ptr = xx; | ||
112 | } | ||
113 | public IntPtr ptr; | ||
114 | |||
115 | public override void Clear() | ||
116 | { | ||
117 | ptr = IntPtr.Zero; | ||
118 | } | ||
119 | public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } } | ||
120 | |||
121 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
122 | public override string AddrString | ||
123 | { | ||
124 | get { return ptr.ToString("X"); } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | // We pin the memory passed between the managed and unmanaged code. | ||
129 | GCHandle m_paramsHandle; | ||
130 | private GCHandle m_collisionArrayPinnedHandle; | ||
131 | private GCHandle m_updateArrayPinnedHandle; | ||
132 | |||
133 | // Handle to the callback used by the unmanaged code to call into the managed code. | ||
134 | // Used for debug logging. | ||
135 | // Need to store the handle in a persistant variable so it won't be freed. | ||
136 | private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle; | ||
137 | |||
138 | private BSScene PhysicsScene { get; set; } | ||
139 | |||
140 | public override string BulletEngineName { get { return "BulletUnmanaged"; } } | ||
141 | public override string BulletEngineVersion { get; protected set; } | ||
142 | |||
143 | public BSAPIUnman(string paramName, BSScene physScene) | ||
144 | { | ||
145 | PhysicsScene = physScene; | ||
146 | |||
147 | // Do something fancy with the paramName to get the right DLL implementation | ||
148 | // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc. | ||
149 | if (Util.IsWindows()) | ||
150 | Util.LoadArchSpecificWindowsDll("BulletSim.dll"); | ||
151 | // If not Windows, loading is performed by the | ||
152 | // Mono loader as specified in | ||
153 | // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". | ||
154 | } | ||
155 | |||
156 | // Initialization and simulation | ||
157 | public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | ||
158 | int maxCollisions, ref CollisionDesc[] collisionArray, | ||
159 | int maxUpdates, ref EntityProperties[] updateArray | ||
160 | ) | ||
161 | { | ||
162 | // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code | ||
163 | m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned); | ||
164 | m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned); | ||
165 | m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned); | ||
166 | |||
167 | // If Debug logging level, enable logging from the unmanaged code | ||
168 | m_DebugLogCallbackHandle = null; | ||
169 | if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled) | ||
170 | { | ||
171 | BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); | ||
172 | if (PhysicsScene.PhysicsLogging.Enabled) | ||
173 | // The handle is saved in a variable to make sure it doesn't get freed after this call | ||
174 | m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog); | ||
175 | else | ||
176 | m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger); | ||
177 | } | ||
178 | |||
179 | // Get the version of the DLL | ||
180 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
181 | // BulletEngineVersion = BulletSimAPI.GetVersion2(); | ||
182 | BulletEngineVersion = ""; | ||
183 | |||
184 | // Call the unmanaged code with the buffers and other information | ||
185 | return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(), | ||
186 | maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | ||
187 | maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | ||
188 | m_DebugLogCallbackHandle)); | ||
189 | |||
190 | } | ||
191 | |||
192 | // Called directly from unmanaged code so don't do much | ||
193 | private void BulletLogger(string msg) | ||
194 | { | ||
195 | BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg); | ||
196 | } | ||
197 | |||
198 | // Called directly from unmanaged code so don't do much | ||
199 | private void BulletLoggerPhysLog(string msg) | ||
200 | { | ||
201 | PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg); | ||
202 | } | ||
203 | |||
204 | public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
205 | out int updatedEntityCount, out int collidersCount) | ||
206 | { | ||
207 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
208 | return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); | ||
209 | } | ||
210 | |||
211 | public override void Shutdown(BulletWorld world) | ||
212 | { | ||
213 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
214 | BSAPICPP.Shutdown2(worldu.ptr); | ||
215 | |||
216 | if (m_paramsHandle.IsAllocated) | ||
217 | { | ||
218 | m_paramsHandle.Free(); | ||
219 | } | ||
220 | if (m_collisionArrayPinnedHandle.IsAllocated) | ||
221 | { | ||
222 | m_collisionArrayPinnedHandle.Free(); | ||
223 | } | ||
224 | if (m_updateArrayPinnedHandle.IsAllocated) | ||
225 | { | ||
226 | m_updateArrayPinnedHandle.Free(); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | public override bool PushUpdate(BulletBody obj) | ||
231 | { | ||
232 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
233 | return BSAPICPP.PushUpdate2(bodyu.ptr); | ||
234 | } | ||
235 | |||
236 | public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) | ||
237 | { | ||
238 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
239 | return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value); | ||
240 | } | ||
241 | |||
242 | // ===================================================================================== | ||
243 | // Mesh, hull, shape and body creation helper routines | ||
244 | public override BulletShape CreateMeshShape(BulletWorld world, | ||
245 | int indicesCount, int[] indices, | ||
246 | int verticesCount, float[] vertices) | ||
247 | { | ||
248 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
249 | return new BulletShapeUnman( | ||
250 | BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), | ||
251 | BSPhysicsShapeType.SHAPE_MESH); | ||
252 | } | ||
253 | |||
254 | public override BulletShape CreateGImpactShape(BulletWorld world, | ||
255 | int indicesCount, int[] indices, | ||
256 | int verticesCount, float[] vertices) | ||
257 | { | ||
258 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
259 | return new BulletShapeUnman( | ||
260 | BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), | ||
261 | BSPhysicsShapeType.SHAPE_GIMPACT); | ||
262 | } | ||
263 | |||
264 | public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) | ||
265 | { | ||
266 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
267 | return new BulletShapeUnman( | ||
268 | BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), | ||
269 | BSPhysicsShapeType.SHAPE_HULL); | ||
270 | } | ||
271 | |||
272 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) | ||
273 | { | ||
274 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
275 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | ||
276 | return new BulletShapeUnman( | ||
277 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms), | ||
278 | BSPhysicsShapeType.SHAPE_HULL); | ||
279 | } | ||
280 | |||
281 | public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
282 | { | ||
283 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
284 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | ||
285 | return new BulletShapeUnman( | ||
286 | BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr), | ||
287 | BSPhysicsShapeType.SHAPE_CONVEXHULL); | ||
288 | } | ||
289 | |||
290 | public override BulletShape CreateConvexHullShape(BulletWorld world, | ||
291 | int indicesCount, int[] indices, | ||
292 | int verticesCount, float[] vertices) | ||
293 | { | ||
294 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
295 | return new BulletShapeUnman( | ||
296 | BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), | ||
297 | BSPhysicsShapeType.SHAPE_CONVEXHULL); | ||
298 | } | ||
299 | |||
300 | public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) | ||
301 | { | ||
302 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
303 | return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type); | ||
304 | } | ||
305 | |||
306 | public override bool IsNativeShape(BulletShape shape) | ||
307 | { | ||
308 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
309 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
310 | return BSAPICPP.IsNativeShape2(shapeu.ptr); | ||
311 | return false; | ||
312 | } | ||
313 | |||
314 | public override void SetShapeCollisionMargin(BulletShape shape, float margin) | ||
315 | { | ||
316 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
317 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
318 | BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin); | ||
319 | } | ||
320 | |||
321 | public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) | ||
322 | { | ||
323 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
324 | return new BulletShapeUnman( | ||
325 | BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale), | ||
326 | BSPhysicsShapeType.SHAPE_CAPSULE); | ||
327 | } | ||
328 | |||
329 | public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree) | ||
330 | { | ||
331 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
332 | return new BulletShapeUnman( | ||
333 | BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree), | ||
334 | BSPhysicsShapeType.SHAPE_COMPOUND); | ||
335 | |||
336 | } | ||
337 | |||
338 | public override int GetNumberOfCompoundChildren(BulletShape shape) | ||
339 | { | ||
340 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
341 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
342 | return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot) | ||
347 | { | ||
348 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
349 | BulletShapeUnman addShapeu = addShape as BulletShapeUnman; | ||
350 | BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot); | ||
351 | } | ||
352 | |||
353 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) | ||
354 | { | ||
355 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
356 | return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
357 | } | ||
358 | |||
359 | public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) | ||
360 | { | ||
361 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
362 | return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
363 | } | ||
364 | |||
365 | public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape) | ||
366 | { | ||
367 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
368 | BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman; | ||
369 | BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); | ||
370 | } | ||
371 | |||
372 | public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) | ||
373 | { | ||
374 | BulletShapeUnman shapeu = pShape as BulletShapeUnman; | ||
375 | BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb); | ||
376 | } | ||
377 | |||
378 | public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) | ||
379 | { | ||
380 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
381 | BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr); | ||
382 | } | ||
383 | |||
384 | public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id) | ||
385 | { | ||
386 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
387 | BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; | ||
388 | return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType); | ||
389 | } | ||
390 | |||
391 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) | ||
392 | { | ||
393 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
394 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
395 | return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr); | ||
396 | } | ||
397 | |||
398 | public override CollisionObjectTypes GetBodyType(BulletBody obj) | ||
399 | { | ||
400 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
401 | return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr); | ||
402 | } | ||
403 | |||
404 | public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
405 | { | ||
406 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
407 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
408 | return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); | ||
409 | } | ||
410 | |||
411 | public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
412 | { | ||
413 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
414 | return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot)); | ||
415 | } | ||
416 | |||
417 | public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
418 | { | ||
419 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
420 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
421 | return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); | ||
422 | } | ||
423 | |||
424 | public override void DestroyObject(BulletWorld world, BulletBody obj) | ||
425 | { | ||
426 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
427 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
428 | BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr); | ||
429 | } | ||
430 | |||
431 | // ===================================================================================== | ||
432 | // Terrain creation and helper routines | ||
433 | public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin) | ||
434 | { | ||
435 | return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); | ||
436 | } | ||
437 | |||
438 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
439 | float scaleFactor, float collisionMargin) | ||
440 | { | ||
441 | return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin), | ||
442 | BSPhysicsShapeType.SHAPE_TERRAIN); | ||
443 | } | ||
444 | |||
445 | // ===================================================================================== | ||
446 | // Constraint creation and helper routines | ||
447 | public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
448 | Vector3 frame1loc, Quaternion frame1rot, | ||
449 | Vector3 frame2loc, Quaternion frame2rot, | ||
450 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
451 | { | ||
452 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
453 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
454 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
455 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
456 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
457 | } | ||
458 | |||
459 | public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
460 | Vector3 joinPoint, | ||
461 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
462 | { | ||
463 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
464 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
465 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
466 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, | ||
467 | joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
468 | } | ||
469 | |||
470 | public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, | ||
471 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
472 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) | ||
473 | { | ||
474 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
475 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
476 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr, | ||
477 | frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies)); | ||
478 | } | ||
479 | |||
480 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
481 | Vector3 frame1loc, Quaternion frame1rot, | ||
482 | Vector3 frame2loc, Quaternion frame2rot, | ||
483 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
484 | { | ||
485 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
486 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
487 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
488 | return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
489 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
490 | } | ||
491 | |||
492 | public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
493 | Vector3 pivotinA, Vector3 pivotinB, | ||
494 | Vector3 axisInA, Vector3 axisInB, | ||
495 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
496 | { | ||
497 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
498 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
499 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
500 | return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, | ||
501 | pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
502 | } | ||
503 | |||
504 | public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
505 | Vector3 frame1loc, Quaternion frame1rot, | ||
506 | Vector3 frame2loc, Quaternion frame2rot, | ||
507 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
508 | { | ||
509 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
510 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
511 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
512 | return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
513 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
514 | } | ||
515 | |||
516 | public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
517 | Vector3 frame1loc, Quaternion frame1rot, | ||
518 | Vector3 frame2loc, Quaternion frame2rot, | ||
519 | bool disableCollisionsBetweenLinkedBodies) | ||
520 | { | ||
521 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
522 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
523 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
524 | return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
525 | frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies)); | ||
526 | } | ||
527 | |||
528 | public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
529 | Vector3 axisInA, Vector3 axisInB, | ||
530 | float ratio, bool disableCollisionsBetweenLinkedBodies) | ||
531 | { | ||
532 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
533 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
534 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
535 | return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB, | ||
536 | ratio, disableCollisionsBetweenLinkedBodies)); | ||
537 | } | ||
538 | |||
539 | public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
540 | Vector3 pivotInA, Vector3 pivotInB, | ||
541 | bool disableCollisionsBetweenLinkedBodies) | ||
542 | { | ||
543 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
544 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
545 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
546 | return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB, | ||
547 | disableCollisionsBetweenLinkedBodies)); | ||
548 | } | ||
549 | |||
550 | public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) | ||
551 | { | ||
552 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
553 | BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse); | ||
554 | } | ||
555 | |||
556 | public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations) | ||
557 | { | ||
558 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
559 | BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations); | ||
560 | } | ||
561 | |||
562 | public override bool SetFrames(BulletConstraint constrain, | ||
563 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) | ||
564 | { | ||
565 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
566 | return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot); | ||
567 | } | ||
568 | |||
569 | public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) | ||
570 | { | ||
571 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
572 | return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi); | ||
573 | } | ||
574 | |||
575 | public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) | ||
576 | { | ||
577 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
578 | return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi); | ||
579 | } | ||
580 | |||
581 | public override bool UseFrameOffset(BulletConstraint constrain, float enable) | ||
582 | { | ||
583 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
584 | return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable); | ||
585 | } | ||
586 | |||
587 | public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce) | ||
588 | { | ||
589 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
590 | return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce); | ||
591 | } | ||
592 | |||
593 | public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold) | ||
594 | { | ||
595 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
596 | return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); | ||
597 | } | ||
598 | |||
599 | public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation) | ||
600 | { | ||
601 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
602 | return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation); | ||
603 | } | ||
604 | |||
605 | public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse) | ||
606 | { | ||
607 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
608 | return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse); | ||
609 | } | ||
610 | |||
611 | public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint) | ||
612 | { | ||
613 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
614 | return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint); | ||
615 | } | ||
616 | |||
617 | public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss) | ||
618 | { | ||
619 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
620 | return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss); | ||
621 | } | ||
622 | |||
623 | public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping) | ||
624 | { | ||
625 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
626 | return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping); | ||
627 | } | ||
628 | |||
629 | public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val) | ||
630 | { | ||
631 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
632 | return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val); | ||
633 | } | ||
634 | |||
635 | public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val) | ||
636 | { | ||
637 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
638 | return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val); | ||
639 | } | ||
640 | |||
641 | public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse) | ||
642 | { | ||
643 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
644 | return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse); | ||
645 | } | ||
646 | |||
647 | public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val) | ||
648 | { | ||
649 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
650 | return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val); | ||
651 | } | ||
652 | |||
653 | public override bool CalculateTransforms(BulletConstraint constrain) | ||
654 | { | ||
655 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
656 | return BSAPICPP.CalculateTransforms2(constrainu.ptr); | ||
657 | } | ||
658 | |||
659 | public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis) | ||
660 | { | ||
661 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
662 | return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis); | ||
663 | } | ||
664 | |||
665 | public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain) | ||
666 | { | ||
667 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
668 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
669 | return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr); | ||
670 | } | ||
671 | |||
672 | // ===================================================================================== | ||
673 | // btCollisionWorld entries | ||
674 | public override void UpdateSingleAabb(BulletWorld world, BulletBody obj) | ||
675 | { | ||
676 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
677 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
678 | BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr); | ||
679 | } | ||
680 | |||
681 | public override void UpdateAabbs(BulletWorld world) | ||
682 | { | ||
683 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
684 | BSAPICPP.UpdateAabbs2(worldu.ptr); | ||
685 | } | ||
686 | |||
687 | public override bool GetForceUpdateAllAabbs(BulletWorld world) | ||
688 | { | ||
689 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
690 | return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr); | ||
691 | } | ||
692 | |||
693 | public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) | ||
694 | { | ||
695 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
696 | BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force); | ||
697 | } | ||
698 | |||
699 | // ===================================================================================== | ||
700 | // btDynamicsWorld entries | ||
701 | public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) | ||
702 | { | ||
703 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
704 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
705 | |||
706 | // Bullet resets several variables when an object is added to the world. | ||
707 | // Gravity is reset to world default depending on the static/dynamic | ||
708 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | ||
709 | Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); | ||
710 | |||
711 | bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); | ||
712 | |||
713 | if (ret) | ||
714 | { | ||
715 | BSAPICPP.SetGravity2(bodyu.ptr, origGrav); | ||
716 | obj.ApplyCollisionMask(world.physicsScene); | ||
717 | } | ||
718 | return ret; | ||
719 | } | ||
720 | |||
721 | public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj) | ||
722 | { | ||
723 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
724 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
725 | return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); | ||
726 | } | ||
727 | |||
728 | public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj) | ||
729 | { | ||
730 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
731 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
732 | return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr); | ||
733 | } | ||
734 | |||
735 | public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) | ||
736 | { | ||
737 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
738 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
739 | return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects); | ||
740 | } | ||
741 | |||
742 | public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) | ||
743 | { | ||
744 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
745 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
746 | return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr); | ||
747 | } | ||
748 | // ===================================================================================== | ||
749 | // btCollisionObject entries | ||
750 | public override Vector3 GetAnisotripicFriction(BulletConstraint constrain) | ||
751 | { | ||
752 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
753 | return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr); | ||
754 | } | ||
755 | |||
756 | public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict) | ||
757 | { | ||
758 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
759 | return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict); | ||
760 | } | ||
761 | |||
762 | public override bool HasAnisotripicFriction(BulletConstraint constrain) | ||
763 | { | ||
764 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
765 | return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr); | ||
766 | } | ||
767 | |||
768 | public override void SetContactProcessingThreshold(BulletBody obj, float val) | ||
769 | { | ||
770 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
771 | BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val); | ||
772 | } | ||
773 | |||
774 | public override float GetContactProcessingThreshold(BulletBody obj) | ||
775 | { | ||
776 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
777 | return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr); | ||
778 | } | ||
779 | |||
780 | public override bool IsStaticObject(BulletBody obj) | ||
781 | { | ||
782 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
783 | return BSAPICPP.IsStaticObject2(bodyu.ptr); | ||
784 | } | ||
785 | |||
786 | public override bool IsKinematicObject(BulletBody obj) | ||
787 | { | ||
788 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
789 | return BSAPICPP.IsKinematicObject2(bodyu.ptr); | ||
790 | } | ||
791 | |||
792 | public override bool IsStaticOrKinematicObject(BulletBody obj) | ||
793 | { | ||
794 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
795 | return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr); | ||
796 | } | ||
797 | |||
798 | public override bool HasContactResponse(BulletBody obj) | ||
799 | { | ||
800 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
801 | return BSAPICPP.HasContactResponse2(bodyu.ptr); | ||
802 | } | ||
803 | |||
804 | public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape) | ||
805 | { | ||
806 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
807 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
808 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
809 | if (worldu != null && bodyu != null) | ||
810 | { | ||
811 | // Special case to allow the caller to zero out the reference to any physical shape | ||
812 | if (shapeu != null) | ||
813 | BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr); | ||
814 | else | ||
815 | BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero); | ||
816 | } | ||
817 | } | ||
818 | |||
819 | public override BulletShape GetCollisionShape(BulletBody obj) | ||
820 | { | ||
821 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
822 | return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
823 | } | ||
824 | |||
825 | public override int GetActivationState(BulletBody obj) | ||
826 | { | ||
827 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
828 | return BSAPICPP.GetActivationState2(bodyu.ptr); | ||
829 | } | ||
830 | |||
831 | public override void SetActivationState(BulletBody obj, int state) | ||
832 | { | ||
833 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
834 | BSAPICPP.SetActivationState2(bodyu.ptr, state); | ||
835 | } | ||
836 | |||
837 | public override void SetDeactivationTime(BulletBody obj, float dtime) | ||
838 | { | ||
839 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
840 | BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime); | ||
841 | } | ||
842 | |||
843 | public override float GetDeactivationTime(BulletBody obj) | ||
844 | { | ||
845 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
846 | return BSAPICPP.GetDeactivationTime2(bodyu.ptr); | ||
847 | } | ||
848 | |||
849 | public override void ForceActivationState(BulletBody obj, ActivationState state) | ||
850 | { | ||
851 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
852 | BSAPICPP.ForceActivationState2(bodyu.ptr, state); | ||
853 | } | ||
854 | |||
855 | public override void Activate(BulletBody obj, bool forceActivation) | ||
856 | { | ||
857 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
858 | BSAPICPP.Activate2(bodyu.ptr, forceActivation); | ||
859 | } | ||
860 | |||
861 | public override bool IsActive(BulletBody obj) | ||
862 | { | ||
863 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
864 | return BSAPICPP.IsActive2(bodyu.ptr); | ||
865 | } | ||
866 | |||
867 | public override void SetRestitution(BulletBody obj, float val) | ||
868 | { | ||
869 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
870 | BSAPICPP.SetRestitution2(bodyu.ptr, val); | ||
871 | } | ||
872 | |||
873 | public override float GetRestitution(BulletBody obj) | ||
874 | { | ||
875 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
876 | return BSAPICPP.GetRestitution2(bodyu.ptr); | ||
877 | } | ||
878 | |||
879 | public override void SetFriction(BulletBody obj, float val) | ||
880 | { | ||
881 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
882 | BSAPICPP.SetFriction2(bodyu.ptr, val); | ||
883 | } | ||
884 | |||
885 | public override float GetFriction(BulletBody obj) | ||
886 | { | ||
887 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
888 | return BSAPICPP.GetFriction2(bodyu.ptr); | ||
889 | } | ||
890 | |||
891 | public override Vector3 GetPosition(BulletBody obj) | ||
892 | { | ||
893 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
894 | return BSAPICPP.GetPosition2(bodyu.ptr); | ||
895 | } | ||
896 | |||
897 | public override Quaternion GetOrientation(BulletBody obj) | ||
898 | { | ||
899 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
900 | return BSAPICPP.GetOrientation2(bodyu.ptr); | ||
901 | } | ||
902 | |||
903 | public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation) | ||
904 | { | ||
905 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
906 | BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation); | ||
907 | } | ||
908 | |||
909 | /* | ||
910 | public override IntPtr GetBroadphaseHandle(BulletBody obj) | ||
911 | { | ||
912 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
913 | return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr); | ||
914 | } | ||
915 | |||
916 | public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle) | ||
917 | { | ||
918 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
919 | BSAPICPP.SetUserPointer2(bodyu.ptr, handle); | ||
920 | } | ||
921 | */ | ||
922 | |||
923 | public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel) | ||
924 | { | ||
925 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
926 | BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel); | ||
927 | } | ||
928 | |||
929 | public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel) | ||
930 | { | ||
931 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
932 | BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel); | ||
933 | } | ||
934 | |||
935 | public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel) | ||
936 | { | ||
937 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
938 | BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel); | ||
939 | } | ||
940 | |||
941 | public override float GetHitFraction(BulletBody obj) | ||
942 | { | ||
943 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
944 | return BSAPICPP.GetHitFraction2(bodyu.ptr); | ||
945 | } | ||
946 | |||
947 | public override void SetHitFraction(BulletBody obj, float val) | ||
948 | { | ||
949 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
950 | BSAPICPP.SetHitFraction2(bodyu.ptr, val); | ||
951 | } | ||
952 | |||
953 | public override CollisionFlags GetCollisionFlags(BulletBody obj) | ||
954 | { | ||
955 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
956 | return BSAPICPP.GetCollisionFlags2(bodyu.ptr); | ||
957 | } | ||
958 | |||
959 | public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
960 | { | ||
961 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
962 | return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags); | ||
963 | } | ||
964 | |||
965 | public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
966 | { | ||
967 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
968 | return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags); | ||
969 | } | ||
970 | |||
971 | public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
972 | { | ||
973 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
974 | return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags); | ||
975 | } | ||
976 | |||
977 | public override float GetCcdMotionThreshold(BulletBody obj) | ||
978 | { | ||
979 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
980 | return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr); | ||
981 | } | ||
982 | |||
983 | |||
984 | public override void SetCcdMotionThreshold(BulletBody obj, float val) | ||
985 | { | ||
986 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
987 | BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val); | ||
988 | } | ||
989 | |||
990 | public override float GetCcdSweptSphereRadius(BulletBody obj) | ||
991 | { | ||
992 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
993 | return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr); | ||
994 | } | ||
995 | |||
996 | public override void SetCcdSweptSphereRadius(BulletBody obj, float val) | ||
997 | { | ||
998 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
999 | BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val); | ||
1000 | } | ||
1001 | |||
1002 | public override IntPtr GetUserPointer(BulletBody obj) | ||
1003 | { | ||
1004 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1005 | return BSAPICPP.GetUserPointer2(bodyu.ptr); | ||
1006 | } | ||
1007 | |||
1008 | public override void SetUserPointer(BulletBody obj, IntPtr val) | ||
1009 | { | ||
1010 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1011 | BSAPICPP.SetUserPointer2(bodyu.ptr, val); | ||
1012 | } | ||
1013 | |||
1014 | // ===================================================================================== | ||
1015 | // btRigidBody entries | ||
1016 | public override void ApplyGravity(BulletBody obj) | ||
1017 | { | ||
1018 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1019 | BSAPICPP.ApplyGravity2(bodyu.ptr); | ||
1020 | } | ||
1021 | |||
1022 | public override void SetGravity(BulletBody obj, Vector3 val) | ||
1023 | { | ||
1024 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1025 | BSAPICPP.SetGravity2(bodyu.ptr, val); | ||
1026 | } | ||
1027 | |||
1028 | public override Vector3 GetGravity(BulletBody obj) | ||
1029 | { | ||
1030 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1031 | return BSAPICPP.GetGravity2(bodyu.ptr); | ||
1032 | } | ||
1033 | |||
1034 | public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping) | ||
1035 | { | ||
1036 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1037 | BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping); | ||
1038 | } | ||
1039 | |||
1040 | public override void SetLinearDamping(BulletBody obj, float lin_damping) | ||
1041 | { | ||
1042 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1043 | BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping); | ||
1044 | } | ||
1045 | |||
1046 | public override void SetAngularDamping(BulletBody obj, float ang_damping) | ||
1047 | { | ||
1048 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1049 | BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping); | ||
1050 | } | ||
1051 | |||
1052 | public override float GetLinearDamping(BulletBody obj) | ||
1053 | { | ||
1054 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1055 | return BSAPICPP.GetLinearDamping2(bodyu.ptr); | ||
1056 | } | ||
1057 | |||
1058 | public override float GetAngularDamping(BulletBody obj) | ||
1059 | { | ||
1060 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1061 | return BSAPICPP.GetAngularDamping2(bodyu.ptr); | ||
1062 | } | ||
1063 | |||
1064 | public override float GetLinearSleepingThreshold(BulletBody obj) | ||
1065 | { | ||
1066 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1067 | return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr); | ||
1068 | } | ||
1069 | |||
1070 | public override void ApplyDamping(BulletBody obj, float timeStep) | ||
1071 | { | ||
1072 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1073 | BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep); | ||
1074 | } | ||
1075 | |||
1076 | public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia) | ||
1077 | { | ||
1078 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1079 | BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia); | ||
1080 | } | ||
1081 | |||
1082 | public override Vector3 GetLinearFactor(BulletBody obj) | ||
1083 | { | ||
1084 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1085 | return BSAPICPP.GetLinearFactor2(bodyu.ptr); | ||
1086 | } | ||
1087 | |||
1088 | public override void SetLinearFactor(BulletBody obj, Vector3 factor) | ||
1089 | { | ||
1090 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1091 | BSAPICPP.SetLinearFactor2(bodyu.ptr, factor); | ||
1092 | } | ||
1093 | |||
1094 | public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) | ||
1095 | { | ||
1096 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1097 | BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot); | ||
1098 | } | ||
1099 | |||
1100 | // Add a force to the object as if its mass is one. | ||
1101 | // Deep down in Bullet: m_totalForce += force*m_linearFactor; | ||
1102 | public override void ApplyCentralForce(BulletBody obj, Vector3 force) | ||
1103 | { | ||
1104 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1105 | BSAPICPP.ApplyCentralForce2(bodyu.ptr, force); | ||
1106 | } | ||
1107 | |||
1108 | // Set the force being applied to the object as if its mass is one. | ||
1109 | public override void SetObjectForce(BulletBody obj, Vector3 force) | ||
1110 | { | ||
1111 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1112 | BSAPICPP.SetObjectForce2(bodyu.ptr, force); | ||
1113 | } | ||
1114 | |||
1115 | public override Vector3 GetTotalForce(BulletBody obj) | ||
1116 | { | ||
1117 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1118 | return BSAPICPP.GetTotalForce2(bodyu.ptr); | ||
1119 | } | ||
1120 | |||
1121 | public override Vector3 GetTotalTorque(BulletBody obj) | ||
1122 | { | ||
1123 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1124 | return BSAPICPP.GetTotalTorque2(bodyu.ptr); | ||
1125 | } | ||
1126 | |||
1127 | public override Vector3 GetInvInertiaDiagLocal(BulletBody obj) | ||
1128 | { | ||
1129 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1130 | return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr); | ||
1131 | } | ||
1132 | |||
1133 | public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert) | ||
1134 | { | ||
1135 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1136 | BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert); | ||
1137 | } | ||
1138 | |||
1139 | public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold) | ||
1140 | { | ||
1141 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1142 | BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); | ||
1143 | } | ||
1144 | |||
1145 | // Deep down in Bullet: m_totalTorque += torque*m_angularFactor; | ||
1146 | public override void ApplyTorque(BulletBody obj, Vector3 torque) | ||
1147 | { | ||
1148 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1149 | BSAPICPP.ApplyTorque2(bodyu.ptr, torque); | ||
1150 | } | ||
1151 | |||
1152 | // Apply force at the given point. Will add torque to the object. | ||
1153 | // Deep down in Bullet: applyCentralForce(force); | ||
1154 | // applyTorque(rel_pos.cross(force*m_linearFactor)); | ||
1155 | public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) | ||
1156 | { | ||
1157 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1158 | BSAPICPP.ApplyForce2(bodyu.ptr, force, pos); | ||
1159 | } | ||
1160 | |||
1161 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
1162 | // Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass; | ||
1163 | public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) | ||
1164 | { | ||
1165 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1166 | BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp); | ||
1167 | } | ||
1168 | |||
1169 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
1170 | // Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; | ||
1171 | public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) | ||
1172 | { | ||
1173 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1174 | BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp); | ||
1175 | } | ||
1176 | |||
1177 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
1178 | // Deep down in Bullet: applyCentralImpulse(impulse); | ||
1179 | // applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor)); | ||
1180 | public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) | ||
1181 | { | ||
1182 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1183 | BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos); | ||
1184 | } | ||
1185 | |||
1186 | public override void ClearForces(BulletBody obj) | ||
1187 | { | ||
1188 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1189 | BSAPICPP.ClearForces2(bodyu.ptr); | ||
1190 | } | ||
1191 | |||
1192 | public override void ClearAllForces(BulletBody obj) | ||
1193 | { | ||
1194 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1195 | BSAPICPP.ClearAllForces2(bodyu.ptr); | ||
1196 | } | ||
1197 | |||
1198 | public override void UpdateInertiaTensor(BulletBody obj) | ||
1199 | { | ||
1200 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1201 | BSAPICPP.UpdateInertiaTensor2(bodyu.ptr); | ||
1202 | } | ||
1203 | |||
1204 | public override Vector3 GetLinearVelocity(BulletBody obj) | ||
1205 | { | ||
1206 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1207 | return BSAPICPP.GetLinearVelocity2(bodyu.ptr); | ||
1208 | } | ||
1209 | |||
1210 | public override Vector3 GetAngularVelocity(BulletBody obj) | ||
1211 | { | ||
1212 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1213 | return BSAPICPP.GetAngularVelocity2(bodyu.ptr); | ||
1214 | } | ||
1215 | |||
1216 | public override void SetLinearVelocity(BulletBody obj, Vector3 vel) | ||
1217 | { | ||
1218 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1219 | BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel); | ||
1220 | } | ||
1221 | |||
1222 | public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity) | ||
1223 | { | ||
1224 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1225 | BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity); | ||
1226 | } | ||
1227 | |||
1228 | public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos) | ||
1229 | { | ||
1230 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1231 | return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos); | ||
1232 | } | ||
1233 | |||
1234 | public override void Translate(BulletBody obj, Vector3 trans) | ||
1235 | { | ||
1236 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1237 | BSAPICPP.Translate2(bodyu.ptr, trans); | ||
1238 | } | ||
1239 | |||
1240 | public override void UpdateDeactivation(BulletBody obj, float timeStep) | ||
1241 | { | ||
1242 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1243 | BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep); | ||
1244 | } | ||
1245 | |||
1246 | public override bool WantsSleeping(BulletBody obj) | ||
1247 | { | ||
1248 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1249 | return BSAPICPP.WantsSleeping2(bodyu.ptr); | ||
1250 | } | ||
1251 | |||
1252 | public override void SetAngularFactor(BulletBody obj, float factor) | ||
1253 | { | ||
1254 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1255 | BSAPICPP.SetAngularFactor2(bodyu.ptr, factor); | ||
1256 | } | ||
1257 | |||
1258 | public override void SetAngularFactorV(BulletBody obj, Vector3 factor) | ||
1259 | { | ||
1260 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1261 | BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor); | ||
1262 | } | ||
1263 | |||
1264 | public override Vector3 GetAngularFactor(BulletBody obj) | ||
1265 | { | ||
1266 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1267 | return BSAPICPP.GetAngularFactor2(bodyu.ptr); | ||
1268 | } | ||
1269 | |||
1270 | public override bool IsInWorld(BulletWorld world, BulletBody obj) | ||
1271 | { | ||
1272 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1273 | return BSAPICPP.IsInWorld2(bodyu.ptr); | ||
1274 | } | ||
1275 | |||
1276 | public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain) | ||
1277 | { | ||
1278 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1279 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1280 | BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr); | ||
1281 | } | ||
1282 | |||
1283 | public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain) | ||
1284 | { | ||
1285 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1286 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1287 | BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr); | ||
1288 | } | ||
1289 | |||
1290 | public override BulletConstraint GetConstraintRef(BulletBody obj, int index) | ||
1291 | { | ||
1292 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1293 | return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index)); | ||
1294 | } | ||
1295 | |||
1296 | public override int GetNumConstraintRefs(BulletBody obj) | ||
1297 | { | ||
1298 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1299 | return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr); | ||
1300 | } | ||
1301 | |||
1302 | public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask) | ||
1303 | { | ||
1304 | BulletBodyUnman bodyu = body as BulletBodyUnman; | ||
1305 | return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask); | ||
1306 | } | ||
1307 | |||
1308 | // ===================================================================================== | ||
1309 | // btCollisionShape entries | ||
1310 | |||
1311 | public override float GetAngularMotionDisc(BulletShape shape) | ||
1312 | { | ||
1313 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1314 | return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr); | ||
1315 | } | ||
1316 | |||
1317 | public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor) | ||
1318 | { | ||
1319 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1320 | return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor); | ||
1321 | } | ||
1322 | |||
1323 | public override bool IsPolyhedral(BulletShape shape) | ||
1324 | { | ||
1325 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1326 | return BSAPICPP.IsPolyhedral2(shapeu.ptr); | ||
1327 | } | ||
1328 | |||
1329 | public override bool IsConvex2d(BulletShape shape) | ||
1330 | { | ||
1331 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1332 | return BSAPICPP.IsConvex2d2(shapeu.ptr); | ||
1333 | } | ||
1334 | |||
1335 | public override bool IsConvex(BulletShape shape) | ||
1336 | { | ||
1337 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1338 | return BSAPICPP.IsConvex2(shapeu.ptr); | ||
1339 | } | ||
1340 | |||
1341 | public override bool IsNonMoving(BulletShape shape) | ||
1342 | { | ||
1343 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1344 | return BSAPICPP.IsNonMoving2(shapeu.ptr); | ||
1345 | } | ||
1346 | |||
1347 | public override bool IsConcave(BulletShape shape) | ||
1348 | { | ||
1349 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1350 | return BSAPICPP.IsConcave2(shapeu.ptr); | ||
1351 | } | ||
1352 | |||
1353 | public override bool IsCompound(BulletShape shape) | ||
1354 | { | ||
1355 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1356 | return BSAPICPP.IsCompound2(shapeu.ptr); | ||
1357 | } | ||
1358 | |||
1359 | public override bool IsSoftBody(BulletShape shape) | ||
1360 | { | ||
1361 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1362 | return BSAPICPP.IsSoftBody2(shapeu.ptr); | ||
1363 | } | ||
1364 | |||
1365 | public override bool IsInfinite(BulletShape shape) | ||
1366 | { | ||
1367 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1368 | return BSAPICPP.IsInfinite2(shapeu.ptr); | ||
1369 | } | ||
1370 | |||
1371 | public override void SetLocalScaling(BulletShape shape, Vector3 scale) | ||
1372 | { | ||
1373 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1374 | BSAPICPP.SetLocalScaling2(shapeu.ptr, scale); | ||
1375 | } | ||
1376 | |||
1377 | public override Vector3 GetLocalScaling(BulletShape shape) | ||
1378 | { | ||
1379 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1380 | return BSAPICPP.GetLocalScaling2(shapeu.ptr); | ||
1381 | } | ||
1382 | |||
1383 | public override Vector3 CalculateLocalInertia(BulletShape shape, float mass) | ||
1384 | { | ||
1385 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1386 | return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass); | ||
1387 | } | ||
1388 | |||
1389 | public override int GetShapeType(BulletShape shape) | ||
1390 | { | ||
1391 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1392 | return BSAPICPP.GetShapeType2(shapeu.ptr); | ||
1393 | } | ||
1394 | |||
1395 | public override void SetMargin(BulletShape shape, float val) | ||
1396 | { | ||
1397 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1398 | BSAPICPP.SetMargin2(shapeu.ptr, val); | ||
1399 | } | ||
1400 | |||
1401 | public override float GetMargin(BulletShape shape) | ||
1402 | { | ||
1403 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1404 | return BSAPICPP.GetMargin2(shapeu.ptr); | ||
1405 | } | ||
1406 | |||
1407 | // ===================================================================================== | ||
1408 | // Debugging | ||
1409 | public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject) | ||
1410 | { | ||
1411 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1412 | BulletBodyUnman bodyu = collisionObject as BulletBodyUnman; | ||
1413 | BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr); | ||
1414 | } | ||
1415 | |||
1416 | public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape) | ||
1417 | { | ||
1418 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1419 | BulletShapeUnman shapeu = collisionShape as BulletShapeUnman; | ||
1420 | BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr); | ||
1421 | } | ||
1422 | |||
1423 | public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) | ||
1424 | { | ||
1425 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1426 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1427 | BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr); | ||
1428 | } | ||
1429 | |||
1430 | public override void DumpActivationInfo(BulletWorld world) | ||
1431 | { | ||
1432 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1433 | BSAPICPP.DumpActivationInfo2(worldu.ptr); | ||
1434 | } | ||
1435 | |||
1436 | public override void DumpAllInfo(BulletWorld world) | ||
1437 | { | ||
1438 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1439 | BSAPICPP.DumpAllInfo2(worldu.ptr); | ||
1440 | } | ||
1441 | |||
1442 | public override void DumpPhysicsStatistics(BulletWorld world) | ||
1443 | { | ||
1444 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1445 | BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); | ||
1446 | } | ||
1447 | public override void ResetBroadphasePool(BulletWorld world) | ||
1448 | { | ||
1449 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1450 | BSAPICPP.ResetBroadphasePool(worldu.ptr); | ||
1451 | } | ||
1452 | public override void ResetConstraintSolver(BulletWorld world) | ||
1453 | { | ||
1454 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1455 | BSAPICPP.ResetConstraintSolver(worldu.ptr); | ||
1456 | } | ||
1457 | |||
1458 | // ===================================================================================== | ||
1459 | // ===================================================================================== | ||
1460 | // ===================================================================================== | ||
1461 | // ===================================================================================== | ||
1462 | // ===================================================================================== | ||
1463 | // The actual interface to the unmanaged code | ||
1464 | static class BSAPICPP | ||
1465 | { | ||
1466 | // =============================================================================== | ||
1467 | // Link back to the managed code for outputting log messages | ||
1468 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
1469 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
1470 | |||
1471 | // =============================================================================== | ||
1472 | // Initialization and simulation | ||
1473 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1474 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, | ||
1475 | int maxCollisions, IntPtr collisionArray, | ||
1476 | int maxUpdates, IntPtr updateArray, | ||
1477 | DebugLogCallback logRoutine); | ||
1478 | |||
1479 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1480 | public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
1481 | out int updatedEntityCount, out int collidersCount); | ||
1482 | |||
1483 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1484 | public static extern void Shutdown2(IntPtr sim); | ||
1485 | |||
1486 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1487 | public static extern bool PushUpdate2(IntPtr obj); | ||
1488 | |||
1489 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1490 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); | ||
1491 | |||
1492 | // ===================================================================================== | ||
1493 | // Mesh, hull, shape and body creation helper routines | ||
1494 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1495 | public static extern IntPtr CreateMeshShape2(IntPtr world, | ||
1496 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1497 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1498 | |||
1499 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1500 | public static extern IntPtr CreateGImpactShape2(IntPtr world, | ||
1501 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1502 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1503 | |||
1504 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1505 | public static extern IntPtr CreateHullShape2(IntPtr world, | ||
1506 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | ||
1507 | |||
1508 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1509 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); | ||
1510 | |||
1511 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1512 | public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
1513 | |||
1514 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1515 | public static extern IntPtr CreateConvexHullShape2(IntPtr world, | ||
1516 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1517 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1518 | |||
1519 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1520 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | ||
1521 | |||
1522 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1523 | public static extern bool IsNativeShape2(IntPtr shape); | ||
1524 | |||
1525 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1526 | public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); | ||
1527 | |||
1528 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1529 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | ||
1530 | |||
1531 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1532 | public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); | ||
1533 | |||
1534 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1535 | public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); | ||
1536 | |||
1537 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1538 | public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); | ||
1539 | |||
1540 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1541 | public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
1542 | |||
1543 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1544 | public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
1545 | |||
1546 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1547 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); | ||
1548 | |||
1549 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1550 | public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); | ||
1551 | |||
1552 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1553 | public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); | ||
1554 | |||
1555 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1556 | public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); | ||
1557 | |||
1558 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1559 | public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); | ||
1560 | |||
1561 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1562 | public static extern int GetBodyType2(IntPtr obj); | ||
1563 | |||
1564 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1565 | public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1566 | |||
1567 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1568 | public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1569 | |||
1570 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1571 | public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1572 | |||
1573 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1574 | public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | ||
1575 | |||
1576 | // ===================================================================================== | ||
1577 | // Terrain creation and helper routines | ||
1578 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1579 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | ||
1580 | |||
1581 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1582 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, | ||
1583 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, | ||
1584 | float scaleFactor, float collisionMargin); | ||
1585 | |||
1586 | // ===================================================================================== | ||
1587 | // Constraint creation and helper routines | ||
1588 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1589 | public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1590 | Vector3 frame1loc, Quaternion frame1rot, | ||
1591 | Vector3 frame2loc, Quaternion frame2rot, | ||
1592 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1593 | |||
1594 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1595 | public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1596 | Vector3 joinPoint, | ||
1597 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1598 | |||
1599 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1600 | public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1, | ||
1601 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1602 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); | ||
1603 | |||
1604 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1605 | public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1606 | Vector3 frame1loc, Quaternion frame1rot, | ||
1607 | Vector3 frame2loc, Quaternion frame2rot, | ||
1608 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1609 | |||
1610 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1611 | public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1612 | Vector3 pivotinA, Vector3 pivotinB, | ||
1613 | Vector3 axisInA, Vector3 axisInB, | ||
1614 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1615 | |||
1616 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1617 | public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1618 | Vector3 frameInAloc, Quaternion frameInArot, | ||
1619 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1620 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1621 | |||
1622 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1623 | public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1624 | Vector3 frameInAloc, Quaternion frameInArot, | ||
1625 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1626 | bool disableCollisionsBetweenLinkedBodies); | ||
1627 | |||
1628 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1629 | public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1630 | Vector3 axisInA, Vector3 axisInB, | ||
1631 | float ratio, bool disableCollisionsBetweenLinkedBodies); | ||
1632 | |||
1633 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1634 | public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1635 | Vector3 pivotInA, Vector3 pivotInB, | ||
1636 | bool disableCollisionsBetweenLinkedBodies); | ||
1637 | |||
1638 | |||
1639 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1640 | public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); | ||
1641 | |||
1642 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1643 | public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); | ||
1644 | |||
1645 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1646 | public static extern bool SetFrames2(IntPtr constrain, | ||
1647 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | ||
1648 | |||
1649 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1650 | public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
1651 | |||
1652 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1653 | public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
1654 | |||
1655 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1656 | public static extern bool UseFrameOffset2(IntPtr constrain, float enable); | ||
1657 | |||
1658 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1659 | public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); | ||
1660 | |||
1661 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1662 | public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); | ||
1663 | |||
1664 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1665 | public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation); | ||
1666 | |||
1667 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1668 | public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse); | ||
1669 | |||
1670 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1671 | public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint); | ||
1672 | |||
1673 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1674 | public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness); | ||
1675 | |||
1676 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1677 | public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping); | ||
1678 | |||
1679 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1680 | public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val); | ||
1681 | |||
1682 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1683 | public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); | ||
1684 | |||
1685 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1686 | public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse); | ||
1687 | |||
1688 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1689 | public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val); | ||
1690 | |||
1691 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1692 | public static extern bool CalculateTransforms2(IntPtr constrain); | ||
1693 | |||
1694 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1695 | public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); | ||
1696 | |||
1697 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1698 | public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); | ||
1699 | |||
1700 | // ===================================================================================== | ||
1701 | // btCollisionWorld entries | ||
1702 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1703 | public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); | ||
1704 | |||
1705 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1706 | public static extern void UpdateAabbs2(IntPtr world); | ||
1707 | |||
1708 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1709 | public static extern bool GetForceUpdateAllAabbs2(IntPtr world); | ||
1710 | |||
1711 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1712 | public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); | ||
1713 | |||
1714 | // ===================================================================================== | ||
1715 | // btDynamicsWorld entries | ||
1716 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1717 | public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); | ||
1718 | |||
1719 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1720 | public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); | ||
1721 | |||
1722 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1723 | public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj); | ||
1724 | |||
1725 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1726 | public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); | ||
1727 | |||
1728 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1729 | public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); | ||
1730 | // ===================================================================================== | ||
1731 | // btCollisionObject entries | ||
1732 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1733 | public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); | ||
1734 | |||
1735 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1736 | public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); | ||
1737 | |||
1738 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1739 | public static extern bool HasAnisotripicFriction2(IntPtr constrain); | ||
1740 | |||
1741 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1742 | public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); | ||
1743 | |||
1744 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1745 | public static extern float GetContactProcessingThreshold2(IntPtr obj); | ||
1746 | |||
1747 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1748 | public static extern bool IsStaticObject2(IntPtr obj); | ||
1749 | |||
1750 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1751 | public static extern bool IsKinematicObject2(IntPtr obj); | ||
1752 | |||
1753 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1754 | public static extern bool IsStaticOrKinematicObject2(IntPtr obj); | ||
1755 | |||
1756 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1757 | public static extern bool HasContactResponse2(IntPtr obj); | ||
1758 | |||
1759 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1760 | public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); | ||
1761 | |||
1762 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1763 | public static extern IntPtr GetCollisionShape2(IntPtr obj); | ||
1764 | |||
1765 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1766 | public static extern int GetActivationState2(IntPtr obj); | ||
1767 | |||
1768 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1769 | public static extern void SetActivationState2(IntPtr obj, int state); | ||
1770 | |||
1771 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1772 | public static extern void SetDeactivationTime2(IntPtr obj, float dtime); | ||
1773 | |||
1774 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1775 | public static extern float GetDeactivationTime2(IntPtr obj); | ||
1776 | |||
1777 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1778 | public static extern void ForceActivationState2(IntPtr obj, ActivationState state); | ||
1779 | |||
1780 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1781 | public static extern void Activate2(IntPtr obj, bool forceActivation); | ||
1782 | |||
1783 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1784 | public static extern bool IsActive2(IntPtr obj); | ||
1785 | |||
1786 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1787 | public static extern void SetRestitution2(IntPtr obj, float val); | ||
1788 | |||
1789 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1790 | public static extern float GetRestitution2(IntPtr obj); | ||
1791 | |||
1792 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1793 | public static extern void SetFriction2(IntPtr obj, float val); | ||
1794 | |||
1795 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1796 | public static extern float GetFriction2(IntPtr obj); | ||
1797 | |||
1798 | /* Haven't defined the type 'Transform' | ||
1799 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1800 | public static extern Transform GetWorldTransform2(IntPtr obj); | ||
1801 | |||
1802 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1803 | public static extern void setWorldTransform2(IntPtr obj, Transform trans); | ||
1804 | */ | ||
1805 | |||
1806 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1807 | public static extern Vector3 GetPosition2(IntPtr obj); | ||
1808 | |||
1809 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1810 | public static extern Quaternion GetOrientation2(IntPtr obj); | ||
1811 | |||
1812 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1813 | public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); | ||
1814 | |||
1815 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1816 | public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); | ||
1817 | |||
1818 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1819 | public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); | ||
1820 | |||
1821 | /* | ||
1822 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1823 | public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); | ||
1824 | |||
1825 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1826 | public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); | ||
1827 | */ | ||
1828 | |||
1829 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1830 | public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); | ||
1831 | |||
1832 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1833 | public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); | ||
1834 | |||
1835 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1836 | public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); | ||
1837 | |||
1838 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1839 | public static extern float GetHitFraction2(IntPtr obj); | ||
1840 | |||
1841 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1842 | public static extern void SetHitFraction2(IntPtr obj, float val); | ||
1843 | |||
1844 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1845 | public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); | ||
1846 | |||
1847 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1848 | public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1849 | |||
1850 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1851 | public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1852 | |||
1853 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1854 | public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1855 | |||
1856 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1857 | public static extern float GetCcdMotionThreshold2(IntPtr obj); | ||
1858 | |||
1859 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1860 | public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); | ||
1861 | |||
1862 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1863 | public static extern float GetCcdSweptSphereRadius2(IntPtr obj); | ||
1864 | |||
1865 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1866 | public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); | ||
1867 | |||
1868 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1869 | public static extern IntPtr GetUserPointer2(IntPtr obj); | ||
1870 | |||
1871 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1872 | public static extern void SetUserPointer2(IntPtr obj, IntPtr val); | ||
1873 | |||
1874 | // ===================================================================================== | ||
1875 | // btRigidBody entries | ||
1876 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1877 | public static extern void ApplyGravity2(IntPtr obj); | ||
1878 | |||
1879 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1880 | public static extern void SetGravity2(IntPtr obj, Vector3 val); | ||
1881 | |||
1882 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1883 | public static extern Vector3 GetGravity2(IntPtr obj); | ||
1884 | |||
1885 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1886 | public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); | ||
1887 | |||
1888 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1889 | public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); | ||
1890 | |||
1891 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1892 | public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); | ||
1893 | |||
1894 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1895 | public static extern float GetLinearDamping2(IntPtr obj); | ||
1896 | |||
1897 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1898 | public static extern float GetAngularDamping2(IntPtr obj); | ||
1899 | |||
1900 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1901 | public static extern float GetLinearSleepingThreshold2(IntPtr obj); | ||
1902 | |||
1903 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1904 | public static extern float GetAngularSleepingThreshold2(IntPtr obj); | ||
1905 | |||
1906 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1907 | public static extern void ApplyDamping2(IntPtr obj, float timeStep); | ||
1908 | |||
1909 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1910 | public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); | ||
1911 | |||
1912 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1913 | public static extern Vector3 GetLinearFactor2(IntPtr obj); | ||
1914 | |||
1915 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1916 | public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); | ||
1917 | |||
1918 | /* | ||
1919 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1920 | public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); | ||
1921 | */ | ||
1922 | |||
1923 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1924 | public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); | ||
1925 | |||
1926 | // Add a force to the object as if its mass is one. | ||
1927 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1928 | public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); | ||
1929 | |||
1930 | // Set the force being applied to the object as if its mass is one. | ||
1931 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1932 | public static extern void SetObjectForce2(IntPtr obj, Vector3 force); | ||
1933 | |||
1934 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1935 | public static extern Vector3 GetTotalForce2(IntPtr obj); | ||
1936 | |||
1937 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1938 | public static extern Vector3 GetTotalTorque2(IntPtr obj); | ||
1939 | |||
1940 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1941 | public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); | ||
1942 | |||
1943 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1944 | public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); | ||
1945 | |||
1946 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1947 | public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); | ||
1948 | |||
1949 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1950 | public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); | ||
1951 | |||
1952 | // Apply force at the given point. Will add torque to the object. | ||
1953 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1954 | public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); | ||
1955 | |||
1956 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
1957 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1958 | public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); | ||
1959 | |||
1960 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
1961 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1962 | public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); | ||
1963 | |||
1964 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
1965 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1966 | public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); | ||
1967 | |||
1968 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1969 | public static extern void ClearForces2(IntPtr obj); | ||
1970 | |||
1971 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1972 | public static extern void ClearAllForces2(IntPtr obj); | ||
1973 | |||
1974 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1975 | public static extern void UpdateInertiaTensor2(IntPtr obj); | ||
1976 | |||
1977 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1978 | public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); | ||
1979 | |||
1980 | /* | ||
1981 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1982 | public static extern Transform GetCenterOfMassTransform2(IntPtr obj); | ||
1983 | */ | ||
1984 | |||
1985 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1986 | public static extern Vector3 GetLinearVelocity2(IntPtr obj); | ||
1987 | |||
1988 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1989 | public static extern Vector3 GetAngularVelocity2(IntPtr obj); | ||
1990 | |||
1991 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1992 | public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); | ||
1993 | |||
1994 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1995 | public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); | ||
1996 | |||
1997 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1998 | public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); | ||
1999 | |||
2000 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2001 | public static extern void Translate2(IntPtr obj, Vector3 trans); | ||
2002 | |||
2003 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2004 | public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); | ||
2005 | |||
2006 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2007 | public static extern bool WantsSleeping2(IntPtr obj); | ||
2008 | |||
2009 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2010 | public static extern void SetAngularFactor2(IntPtr obj, float factor); | ||
2011 | |||
2012 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2013 | public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); | ||
2014 | |||
2015 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2016 | public static extern Vector3 GetAngularFactor2(IntPtr obj); | ||
2017 | |||
2018 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2019 | public static extern bool IsInWorld2(IntPtr obj); | ||
2020 | |||
2021 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2022 | public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); | ||
2023 | |||
2024 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2025 | public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); | ||
2026 | |||
2027 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2028 | public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | ||
2029 | |||
2030 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2031 | public static extern int GetNumConstraintRefs2(IntPtr obj); | ||
2032 | |||
2033 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2034 | public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); | ||
2035 | |||
2036 | // ===================================================================================== | ||
2037 | // btCollisionShape entries | ||
2038 | |||
2039 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2040 | public static extern float GetAngularMotionDisc2(IntPtr shape); | ||
2041 | |||
2042 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2043 | public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); | ||
2044 | |||
2045 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2046 | public static extern bool IsPolyhedral2(IntPtr shape); | ||
2047 | |||
2048 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2049 | public static extern bool IsConvex2d2(IntPtr shape); | ||
2050 | |||
2051 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2052 | public static extern bool IsConvex2(IntPtr shape); | ||
2053 | |||
2054 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2055 | public static extern bool IsNonMoving2(IntPtr shape); | ||
2056 | |||
2057 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2058 | public static extern bool IsConcave2(IntPtr shape); | ||
2059 | |||
2060 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2061 | public static extern bool IsCompound2(IntPtr shape); | ||
2062 | |||
2063 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2064 | public static extern bool IsSoftBody2(IntPtr shape); | ||
2065 | |||
2066 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2067 | public static extern bool IsInfinite2(IntPtr shape); | ||
2068 | |||
2069 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2070 | public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); | ||
2071 | |||
2072 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2073 | public static extern Vector3 GetLocalScaling2(IntPtr shape); | ||
2074 | |||
2075 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2076 | public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); | ||
2077 | |||
2078 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2079 | public static extern int GetShapeType2(IntPtr shape); | ||
2080 | |||
2081 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2082 | public static extern void SetMargin2(IntPtr shape, float val); | ||
2083 | |||
2084 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2085 | public static extern float GetMargin2(IntPtr shape); | ||
2086 | |||
2087 | // ===================================================================================== | ||
2088 | // Debugging | ||
2089 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2090 | public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | ||
2091 | |||
2092 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2093 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | ||
2094 | |||
2095 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2096 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
2097 | |||
2098 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2099 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | ||
2100 | |||
2101 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2102 | public static extern void DumpActivationInfo2(IntPtr sim); | ||
2103 | |||
2104 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2105 | public static extern void DumpAllInfo2(IntPtr sim); | ||
2106 | |||
2107 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2108 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | ||
2109 | |||
2110 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2111 | public static extern void ResetBroadphasePool(IntPtr sim); | ||
2112 | |||
2113 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2114 | public static extern void ResetConstraintSolver(IntPtr sim); | ||
2115 | |||
2116 | } | ||
2117 | |||
2118 | } | ||
2119 | |||
2120 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs new file mode 100755 index 0000000..741f8db --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs | |||
@@ -0,0 +1,2589 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.IO; | ||
30 | using System.Runtime.InteropServices; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Framework; | ||
34 | |||
35 | using OpenMetaverse; | ||
36 | |||
37 | using BulletXNA; | ||
38 | using BulletXNA.LinearMath; | ||
39 | using BulletXNA.BulletCollision; | ||
40 | using BulletXNA.BulletDynamics; | ||
41 | using BulletXNA.BulletCollision.CollisionDispatch; | ||
42 | |||
43 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
44 | { | ||
45 | public sealed class BSAPIXNA : BSAPITemplate | ||
46 | { | ||
47 | private sealed class BulletWorldXNA : BulletWorld | ||
48 | { | ||
49 | public DiscreteDynamicsWorld world; | ||
50 | public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx) | ||
51 | : base(id, physScene) | ||
52 | { | ||
53 | world = xx; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | private sealed class BulletBodyXNA : BulletBody | ||
58 | { | ||
59 | public CollisionObject body; | ||
60 | public RigidBody rigidBody { get { return RigidBody.Upcast(body); } } | ||
61 | |||
62 | public BulletBodyXNA(uint id, CollisionObject xx) | ||
63 | : base(id) | ||
64 | { | ||
65 | body = xx; | ||
66 | } | ||
67 | public override bool HasPhysicalBody | ||
68 | { | ||
69 | get { return body != null; } | ||
70 | } | ||
71 | public override void Clear() | ||
72 | { | ||
73 | body = null; | ||
74 | } | ||
75 | public override string AddrString | ||
76 | { | ||
77 | get { return "XNARigidBody"; } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | private sealed class BulletShapeXNA : BulletShape | ||
82 | { | ||
83 | public CollisionShape shape; | ||
84 | public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) | ||
85 | : base() | ||
86 | { | ||
87 | shape = xx; | ||
88 | shapeType = typ; | ||
89 | } | ||
90 | public override bool HasPhysicalShape | ||
91 | { | ||
92 | get { return shape != null; } | ||
93 | } | ||
94 | public override void Clear() | ||
95 | { | ||
96 | shape = null; | ||
97 | } | ||
98 | public override BulletShape Clone() | ||
99 | { | ||
100 | return new BulletShapeXNA(shape, shapeType); | ||
101 | } | ||
102 | public override bool ReferenceSame(BulletShape other) | ||
103 | { | ||
104 | BulletShapeXNA otheru = other as BulletShapeXNA; | ||
105 | return (otheru != null) && (this.shape == otheru.shape); | ||
106 | |||
107 | } | ||
108 | public override string AddrString | ||
109 | { | ||
110 | get { return "XNACollisionShape"; } | ||
111 | } | ||
112 | } | ||
113 | private sealed class BulletConstraintXNA : BulletConstraint | ||
114 | { | ||
115 | public TypedConstraint constrain; | ||
116 | public BulletConstraintXNA(TypedConstraint xx) : base() | ||
117 | { | ||
118 | constrain = xx; | ||
119 | } | ||
120 | |||
121 | public override void Clear() | ||
122 | { | ||
123 | constrain = null; | ||
124 | } | ||
125 | public override bool HasPhysicalConstraint { get { return constrain != null; } } | ||
126 | |||
127 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
128 | public override string AddrString | ||
129 | { | ||
130 | get { return "XNAConstraint"; } | ||
131 | } | ||
132 | } | ||
133 | internal int m_maxCollisions; | ||
134 | internal CollisionDesc[] UpdatedCollisions; | ||
135 | internal int LastCollisionDesc = 0; | ||
136 | internal int m_maxUpdatesPerFrame; | ||
137 | internal int LastEntityProperty = 0; | ||
138 | |||
139 | internal EntityProperties[] UpdatedObjects; | ||
140 | internal Dictionary<uint, GhostObject> specialCollisionObjects; | ||
141 | |||
142 | private static int m_collisionsThisFrame; | ||
143 | private BSScene PhysicsScene { get; set; } | ||
144 | |||
145 | public override string BulletEngineName { get { return "BulletXNA"; } } | ||
146 | public override string BulletEngineVersion { get; protected set; } | ||
147 | |||
148 | public BSAPIXNA(string paramName, BSScene physScene) | ||
149 | { | ||
150 | PhysicsScene = physScene; | ||
151 | } | ||
152 | |||
153 | /// <summary> | ||
154 | /// | ||
155 | /// </summary> | ||
156 | /// <param name="p"></param> | ||
157 | /// <param name="p_2"></param> | ||
158 | public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) | ||
159 | { | ||
160 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
161 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
162 | CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; | ||
163 | if (body != null) | ||
164 | world.RemoveRigidBody(body); | ||
165 | else if (collisionObject != null) | ||
166 | world.RemoveCollisionObject(collisionObject); | ||
167 | else | ||
168 | return false; | ||
169 | return true; | ||
170 | } | ||
171 | |||
172 | public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody) | ||
173 | { | ||
174 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
175 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
176 | CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; | ||
177 | if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null) | ||
178 | { | ||
179 | world.RemoveCollisionObject(collisionObject); | ||
180 | world.AddCollisionObject(collisionObject); | ||
181 | } | ||
182 | return true; | ||
183 | } | ||
184 | |||
185 | public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) | ||
186 | { | ||
187 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
188 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; | ||
189 | world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); | ||
190 | |||
191 | return true; | ||
192 | |||
193 | } | ||
194 | |||
195 | public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint) | ||
196 | { | ||
197 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
198 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; | ||
199 | world.RemoveConstraint(constraint); | ||
200 | return true; | ||
201 | } | ||
202 | |||
203 | public override void SetRestitution(BulletBody pCollisionObject, float pRestitution) | ||
204 | { | ||
205 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
206 | collisionObject.SetRestitution(pRestitution); | ||
207 | } | ||
208 | |||
209 | public override int GetShapeType(BulletShape pShape) | ||
210 | { | ||
211 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
212 | return (int)shape.GetShapeType(); | ||
213 | } | ||
214 | public override void SetMargin(BulletShape pShape, float pMargin) | ||
215 | { | ||
216 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
217 | shape.SetMargin(pMargin); | ||
218 | } | ||
219 | |||
220 | public override float GetMargin(BulletShape pShape) | ||
221 | { | ||
222 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
223 | return shape.GetMargin(); | ||
224 | } | ||
225 | |||
226 | public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) | ||
227 | { | ||
228 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
229 | IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | ||
230 | shape.SetLocalScaling(ref vec); | ||
231 | |||
232 | } | ||
233 | |||
234 | public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold) | ||
235 | { | ||
236 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
237 | collisionObject.SetContactProcessingThreshold(contactprocessingthreshold); | ||
238 | } | ||
239 | |||
240 | public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold) | ||
241 | { | ||
242 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
243 | collisionObject.SetCcdMotionThreshold(pccdMotionThreashold); | ||
244 | } | ||
245 | |||
246 | public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius) | ||
247 | { | ||
248 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
249 | collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); | ||
250 | } | ||
251 | |||
252 | public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) | ||
253 | { | ||
254 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
255 | body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); | ||
256 | } | ||
257 | |||
258 | public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) | ||
259 | { | ||
260 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
261 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); | ||
262 | existingcollisionFlags |= pcollisionFlags; | ||
263 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | ||
264 | return (CollisionFlags) (uint) existingcollisionFlags; | ||
265 | } | ||
266 | |||
267 | public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) | ||
268 | { | ||
269 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
270 | CollisionObject cbody = (pBody as BulletBodyXNA).body; | ||
271 | RigidBody rbody = cbody as RigidBody; | ||
272 | |||
273 | // Bullet resets several variables when an object is added to the world. In particular, | ||
274 | // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic | ||
275 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | ||
276 | IndexedMatrix origPos = cbody.GetWorldTransform(); | ||
277 | if (rbody != null) | ||
278 | { | ||
279 | IndexedVector3 origGrav = rbody.GetGravity(); | ||
280 | world.AddRigidBody(rbody); | ||
281 | rbody.SetGravity(origGrav); | ||
282 | } | ||
283 | else | ||
284 | { | ||
285 | world.AddCollisionObject(cbody); | ||
286 | } | ||
287 | cbody.SetWorldTransform(origPos); | ||
288 | |||
289 | pBody.ApplyCollisionMask(pWorld.physicsScene); | ||
290 | |||
291 | //if (body.GetBroadphaseHandle() != null) | ||
292 | // world.UpdateSingleAabb(body); | ||
293 | return true; | ||
294 | } | ||
295 | |||
296 | public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState) | ||
297 | { | ||
298 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
299 | collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); | ||
300 | } | ||
301 | |||
302 | public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject) | ||
303 | { | ||
304 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
305 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
306 | world.UpdateSingleAabb(collisionObject); | ||
307 | } | ||
308 | |||
309 | public override void UpdateAabbs(BulletWorld pWorld) { | ||
310 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
311 | world.UpdateAabbs(); | ||
312 | } | ||
313 | public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { | ||
314 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
315 | return world.GetForceUpdateAllAabbs(); | ||
316 | |||
317 | } | ||
318 | public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) | ||
319 | { | ||
320 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
321 | world.SetForceUpdateAllAabbs(pForce); | ||
322 | } | ||
323 | |||
324 | public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask) | ||
325 | { | ||
326 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
327 | collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
328 | collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
329 | if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0) | ||
330 | return false; | ||
331 | return true; | ||
332 | } | ||
333 | |||
334 | public override void ClearAllForces(BulletBody pCollisionObject) | ||
335 | { | ||
336 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
337 | IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); | ||
338 | collisionObject.SetInterpolationLinearVelocity(ref zeroVector); | ||
339 | collisionObject.SetInterpolationAngularVelocity(ref zeroVector); | ||
340 | IndexedMatrix bodytransform = collisionObject.GetWorldTransform(); | ||
341 | |||
342 | collisionObject.SetInterpolationWorldTransform(ref bodytransform); | ||
343 | |||
344 | if (collisionObject is RigidBody) | ||
345 | { | ||
346 | RigidBody rigidbody = collisionObject as RigidBody; | ||
347 | rigidbody.SetLinearVelocity(zeroVector); | ||
348 | rigidbody.SetAngularVelocity(zeroVector); | ||
349 | rigidbody.ClearForces(); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3) | ||
354 | { | ||
355 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
356 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | ||
357 | collisionObject.SetInterpolationAngularVelocity(ref vec); | ||
358 | } | ||
359 | |||
360 | public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) | ||
361 | { | ||
362 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
363 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | ||
364 | body.SetAngularVelocity(ref vec); | ||
365 | } | ||
366 | public override Vector3 GetTotalForce(BulletBody pBody) | ||
367 | { | ||
368 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
369 | IndexedVector3 iv3 = body.GetTotalForce(); | ||
370 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
371 | } | ||
372 | public override Vector3 GetTotalTorque(BulletBody pBody) | ||
373 | { | ||
374 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
375 | IndexedVector3 iv3 = body.GetTotalTorque(); | ||
376 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
377 | } | ||
378 | public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) | ||
379 | { | ||
380 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
381 | IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); | ||
382 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
383 | } | ||
384 | public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) | ||
385 | { | ||
386 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
387 | IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); | ||
388 | body.SetInvInertiaDiagLocal(ref iv3); | ||
389 | } | ||
390 | public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) | ||
391 | { | ||
392 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
393 | IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); | ||
394 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
395 | body.ApplyForce(ref forceiv3, ref posiv3); | ||
396 | } | ||
397 | public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) | ||
398 | { | ||
399 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
400 | IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); | ||
401 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
402 | body.ApplyImpulse(ref impiv3, ref posiv3); | ||
403 | } | ||
404 | |||
405 | public override void ClearForces(BulletBody pBody) | ||
406 | { | ||
407 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
408 | body.ClearForces(); | ||
409 | } | ||
410 | |||
411 | public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation) | ||
412 | { | ||
413 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
414 | IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); | ||
415 | IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, | ||
416 | _orientation.W); | ||
417 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); | ||
418 | mat._origin = vposition; | ||
419 | collisionObject.SetWorldTransform(mat); | ||
420 | |||
421 | } | ||
422 | |||
423 | public override Vector3 GetPosition(BulletBody pCollisionObject) | ||
424 | { | ||
425 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
426 | IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin; | ||
427 | return new Vector3(pos.X, pos.Y, pos.Z); | ||
428 | } | ||
429 | |||
430 | public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) | ||
431 | { | ||
432 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
433 | IndexedVector3 inertia = IndexedVector3.Zero; | ||
434 | shape.CalculateLocalInertia(pphysMass, out inertia); | ||
435 | return new Vector3(inertia.X, inertia.Y, inertia.Z); | ||
436 | } | ||
437 | |||
438 | public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) | ||
439 | { | ||
440 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
441 | if (body != null) // Can't set mass props on collision object. | ||
442 | { | ||
443 | IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); | ||
444 | body.SetMassProps(pphysMass, inertia); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | |||
449 | public override void SetObjectForce(BulletBody pBody, Vector3 _force) | ||
450 | { | ||
451 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
452 | IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); | ||
453 | body.SetTotalForce(ref force); | ||
454 | } | ||
455 | |||
456 | public override void SetFriction(BulletBody pCollisionObject, float _currentFriction) | ||
457 | { | ||
458 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
459 | collisionObject.SetFriction(_currentFriction); | ||
460 | } | ||
461 | |||
462 | public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) | ||
463 | { | ||
464 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
465 | IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); | ||
466 | body.SetLinearVelocity(velocity); | ||
467 | } | ||
468 | |||
469 | public override void Activate(BulletBody pCollisionObject, bool pforceactivation) | ||
470 | { | ||
471 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
472 | collisionObject.Activate(pforceactivation); | ||
473 | |||
474 | } | ||
475 | |||
476 | public override Quaternion GetOrientation(BulletBody pCollisionObject) | ||
477 | { | ||
478 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
479 | IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation(); | ||
480 | return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); | ||
481 | } | ||
482 | |||
483 | public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) | ||
484 | { | ||
485 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
486 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); | ||
487 | existingcollisionFlags &= ~pcollisionFlags; | ||
488 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | ||
489 | return (CollisionFlags)(uint)existingcollisionFlags; | ||
490 | } | ||
491 | |||
492 | public override float GetCcdMotionThreshold(BulletBody pCollisionObject) | ||
493 | { | ||
494 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
495 | return collisionObject.GetCcdSquareMotionThreshold(); | ||
496 | } | ||
497 | |||
498 | public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject) | ||
499 | { | ||
500 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
501 | return collisionObject.GetCcdSweptSphereRadius(); | ||
502 | |||
503 | } | ||
504 | |||
505 | public override IntPtr GetUserPointer(BulletBody pCollisionObject) | ||
506 | { | ||
507 | CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; | ||
508 | return (IntPtr)shape.GetUserPointer(); | ||
509 | } | ||
510 | |||
511 | public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val) | ||
512 | { | ||
513 | CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; | ||
514 | shape.SetUserPointer(val); | ||
515 | } | ||
516 | |||
517 | public override void SetGravity(BulletBody pBody, Vector3 pGravity) | ||
518 | { | ||
519 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
520 | if (body != null) // Can't set collisionobject.set gravity | ||
521 | { | ||
522 | IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); | ||
523 | body.SetGravity(gravity); | ||
524 | } | ||
525 | } | ||
526 | |||
527 | public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) | ||
528 | { | ||
529 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
530 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; | ||
531 | world.RemoveConstraint(constraint); | ||
532 | return true; | ||
533 | } | ||
534 | |||
535 | public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) | ||
536 | { | ||
537 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
538 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | ||
539 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | ||
540 | constraint.SetLinearLowerLimit(lowlimit); | ||
541 | constraint.SetLinearUpperLimit(highlimit); | ||
542 | return true; | ||
543 | } | ||
544 | |||
545 | public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) | ||
546 | { | ||
547 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
548 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | ||
549 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | ||
550 | constraint.SetAngularLowerLimit(lowlimit); | ||
551 | constraint.SetAngularUpperLimit(highlimit); | ||
552 | return true; | ||
553 | } | ||
554 | |||
555 | public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) | ||
556 | { | ||
557 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
558 | constraint.SetOverrideNumSolverIterations((int)cnt); | ||
559 | } | ||
560 | |||
561 | public override bool CalculateTransforms(BulletConstraint pConstraint) | ||
562 | { | ||
563 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
564 | constraint.CalculateTransforms(); | ||
565 | return true; | ||
566 | } | ||
567 | |||
568 | public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) | ||
569 | { | ||
570 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
571 | constraint.SetEnabled((p_2 == 0) ? false : true); | ||
572 | } | ||
573 | |||
574 | |||
575 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
576 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | ||
577 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
578 | |||
579 | { | ||
580 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
581 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
582 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
583 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
584 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
585 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
586 | frame1._origin = frame1v; | ||
587 | |||
588 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
589 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
590 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
591 | frame2._origin = frame1v; | ||
592 | |||
593 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, | ||
594 | puseLinearReferenceFrameA); | ||
595 | consttr.CalculateTransforms(); | ||
596 | world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); | ||
597 | |||
598 | return new BulletConstraintXNA(consttr); | ||
599 | } | ||
600 | |||
601 | public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1, | ||
602 | Vector3 pframe1, Quaternion pframe1rot, | ||
603 | bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies) | ||
604 | { | ||
605 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
606 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
607 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
608 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
609 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
610 | frame1._origin = frame1v; | ||
611 | |||
612 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB); | ||
613 | consttr.CalculateTransforms(); | ||
614 | world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); | ||
615 | |||
616 | return new BulletConstraintXNA(consttr); | ||
617 | } | ||
618 | |||
619 | /// <summary> | ||
620 | /// | ||
621 | /// </summary> | ||
622 | /// <param name="pWorld"></param> | ||
623 | /// <param name="pBody1"></param> | ||
624 | /// <param name="pBody2"></param> | ||
625 | /// <param name="pjoinPoint"></param> | ||
626 | /// <param name="puseLinearReferenceFrameA"></param> | ||
627 | /// <param name="pdisableCollisionsBetweenLinkedBodies"></param> | ||
628 | /// <returns></returns> | ||
629 | public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
630 | { | ||
631 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
632 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
633 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
634 | IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | ||
635 | IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | ||
636 | |||
637 | IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); | ||
638 | IndexedMatrix mat = IndexedMatrix.Identity; | ||
639 | mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); | ||
640 | frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; | ||
641 | frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; | ||
642 | |||
643 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
644 | consttr.CalculateTransforms(); | ||
645 | world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); | ||
646 | |||
647 | return new BulletConstraintXNA(consttr); | ||
648 | } | ||
649 | //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | ||
650 | public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) | ||
651 | { | ||
652 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
653 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
654 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
655 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
656 | frame1._origin = frame1v; | ||
657 | |||
658 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
659 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
660 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
661 | frame2._origin = frame2v; | ||
662 | constraint.SetFrames(ref frame1, ref frame2); | ||
663 | return true; | ||
664 | } | ||
665 | |||
666 | public override Vector3 GetLinearVelocity(BulletBody pBody) | ||
667 | { | ||
668 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
669 | IndexedVector3 iv3 = body.GetLinearVelocity(); | ||
670 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
671 | } | ||
672 | public override Vector3 GetAngularVelocity(BulletBody pBody) | ||
673 | { | ||
674 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
675 | IndexedVector3 iv3 = body.GetAngularVelocity(); | ||
676 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
677 | } | ||
678 | public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) | ||
679 | { | ||
680 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
681 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
682 | IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); | ||
683 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
684 | } | ||
685 | public override void Translate(BulletBody pCollisionObject, Vector3 trans) | ||
686 | { | ||
687 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
688 | collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z)); | ||
689 | } | ||
690 | public override void UpdateDeactivation(BulletBody pBody, float timeStep) | ||
691 | { | ||
692 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
693 | body.UpdateDeactivation(timeStep); | ||
694 | } | ||
695 | |||
696 | public override bool WantsSleeping(BulletBody pBody) | ||
697 | { | ||
698 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
699 | return body.WantsSleeping(); | ||
700 | } | ||
701 | |||
702 | public override void SetAngularFactor(BulletBody pBody, float factor) | ||
703 | { | ||
704 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
705 | body.SetAngularFactor(factor); | ||
706 | } | ||
707 | |||
708 | public override Vector3 GetAngularFactor(BulletBody pBody) | ||
709 | { | ||
710 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
711 | IndexedVector3 iv3 = body.GetAngularFactor(); | ||
712 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
713 | } | ||
714 | |||
715 | public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject) | ||
716 | { | ||
717 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
718 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
719 | return world.IsInWorld(collisionObject); | ||
720 | } | ||
721 | |||
722 | public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint) | ||
723 | { | ||
724 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
725 | TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; | ||
726 | body.AddConstraintRef(constrain); | ||
727 | } | ||
728 | |||
729 | public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint) | ||
730 | { | ||
731 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
732 | TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; | ||
733 | body.RemoveConstraintRef(constrain); | ||
734 | } | ||
735 | |||
736 | public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) | ||
737 | { | ||
738 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
739 | return new BulletConstraintXNA(body.GetConstraintRef(index)); | ||
740 | } | ||
741 | |||
742 | public override int GetNumConstraintRefs(BulletBody pBody) | ||
743 | { | ||
744 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
745 | return body.GetNumConstraintRefs(); | ||
746 | } | ||
747 | |||
748 | public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity) | ||
749 | { | ||
750 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
751 | IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); | ||
752 | collisionObject.SetInterpolationLinearVelocity(ref velocity); | ||
753 | } | ||
754 | |||
755 | public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) | ||
756 | { | ||
757 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
758 | constraint.SetUseFrameOffset((onOff == 0) ? false : true); | ||
759 | return true; | ||
760 | } | ||
761 | //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); | ||
762 | public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) | ||
763 | { | ||
764 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
765 | constraint.SetBreakingImpulseThreshold(threshold); | ||
766 | return true; | ||
767 | } | ||
768 | public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation) | ||
769 | { | ||
770 | HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint; | ||
771 | if (softness == HINGE_NOT_SPECIFIED) | ||
772 | constraint.SetLimit(low, high); | ||
773 | else | ||
774 | constraint.SetLimit(low, high, softness, bias, relaxation); | ||
775 | return true; | ||
776 | } | ||
777 | public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse) | ||
778 | { | ||
779 | Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; | ||
780 | constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true)); | ||
781 | return true; | ||
782 | } | ||
783 | |||
784 | public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint) | ||
785 | { | ||
786 | Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; | ||
787 | if (index == SPRING_NOT_SPECIFIED) | ||
788 | { | ||
789 | constraint.SetEquilibriumPoint(); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | if (equilibriumPoint == SPRING_NOT_SPECIFIED) | ||
794 | constraint.SetEquilibriumPoint(index); | ||
795 | else | ||
796 | constraint.SetEquilibriumPoint(index, equilibriumPoint); | ||
797 | } | ||
798 | return true; | ||
799 | } | ||
800 | |||
801 | public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness) | ||
802 | { | ||
803 | Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; | ||
804 | constraint.SetStiffness(index, stiffness); | ||
805 | return true; | ||
806 | } | ||
807 | |||
808 | public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping) | ||
809 | { | ||
810 | Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; | ||
811 | constraint.SetDamping(index, damping); | ||
812 | return true; | ||
813 | } | ||
814 | |||
815 | public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val) | ||
816 | { | ||
817 | SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; | ||
818 | switch (lowerUpper) | ||
819 | { | ||
820 | case SLIDER_LOWER_LIMIT: | ||
821 | switch (linAng) | ||
822 | { | ||
823 | case SLIDER_LINEAR: | ||
824 | constraint.SetLowerLinLimit(val); | ||
825 | break; | ||
826 | case SLIDER_ANGULAR: | ||
827 | constraint.SetLowerAngLimit(val); | ||
828 | break; | ||
829 | } | ||
830 | break; | ||
831 | case SLIDER_UPPER_LIMIT: | ||
832 | switch (linAng) | ||
833 | { | ||
834 | case SLIDER_LINEAR: | ||
835 | constraint.SetUpperLinLimit(val); | ||
836 | break; | ||
837 | case SLIDER_ANGULAR: | ||
838 | constraint.SetUpperAngLimit(val); | ||
839 | break; | ||
840 | } | ||
841 | break; | ||
842 | } | ||
843 | return true; | ||
844 | } | ||
845 | public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val) | ||
846 | { | ||
847 | SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; | ||
848 | switch (softRestDamp) | ||
849 | { | ||
850 | case SLIDER_SET_SOFTNESS: | ||
851 | switch (dirLimOrtho) | ||
852 | { | ||
853 | case SLIDER_SET_DIRECTION: | ||
854 | switch (linAng) | ||
855 | { | ||
856 | case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break; | ||
857 | case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break; | ||
858 | } | ||
859 | break; | ||
860 | case SLIDER_SET_LIMIT: | ||
861 | switch (linAng) | ||
862 | { | ||
863 | case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break; | ||
864 | case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break; | ||
865 | } | ||
866 | break; | ||
867 | case SLIDER_SET_ORTHO: | ||
868 | switch (linAng) | ||
869 | { | ||
870 | case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break; | ||
871 | case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break; | ||
872 | } | ||
873 | break; | ||
874 | } | ||
875 | break; | ||
876 | case SLIDER_SET_RESTITUTION: | ||
877 | switch (dirLimOrtho) | ||
878 | { | ||
879 | case SLIDER_SET_DIRECTION: | ||
880 | switch (linAng) | ||
881 | { | ||
882 | case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break; | ||
883 | case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break; | ||
884 | } | ||
885 | break; | ||
886 | case SLIDER_SET_LIMIT: | ||
887 | switch (linAng) | ||
888 | { | ||
889 | case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break; | ||
890 | case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break; | ||
891 | } | ||
892 | break; | ||
893 | case SLIDER_SET_ORTHO: | ||
894 | switch (linAng) | ||
895 | { | ||
896 | case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break; | ||
897 | case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break; | ||
898 | } | ||
899 | break; | ||
900 | } | ||
901 | break; | ||
902 | case SLIDER_SET_DAMPING: | ||
903 | switch (dirLimOrtho) | ||
904 | { | ||
905 | case SLIDER_SET_DIRECTION: | ||
906 | switch (linAng) | ||
907 | { | ||
908 | case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break; | ||
909 | case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break; | ||
910 | } | ||
911 | break; | ||
912 | case SLIDER_SET_LIMIT: | ||
913 | switch (linAng) | ||
914 | { | ||
915 | case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break; | ||
916 | case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break; | ||
917 | } | ||
918 | break; | ||
919 | case SLIDER_SET_ORTHO: | ||
920 | switch (linAng) | ||
921 | { | ||
922 | case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break; | ||
923 | case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break; | ||
924 | } | ||
925 | break; | ||
926 | } | ||
927 | break; | ||
928 | } | ||
929 | return true; | ||
930 | } | ||
931 | public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse) | ||
932 | { | ||
933 | SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; | ||
934 | switch (linAng) | ||
935 | { | ||
936 | case SLIDER_LINEAR: | ||
937 | constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true); | ||
938 | break; | ||
939 | case SLIDER_ANGULAR: | ||
940 | constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true); | ||
941 | break; | ||
942 | } | ||
943 | return true; | ||
944 | } | ||
945 | public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val) | ||
946 | { | ||
947 | SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; | ||
948 | switch (forceVel) | ||
949 | { | ||
950 | case SLIDER_MOTOR_VELOCITY: | ||
951 | switch (linAng) | ||
952 | { | ||
953 | case SLIDER_LINEAR: | ||
954 | constraint.SetTargetLinMotorVelocity(val); | ||
955 | break; | ||
956 | case SLIDER_ANGULAR: | ||
957 | constraint.SetTargetAngMotorVelocity(val); | ||
958 | break; | ||
959 | } | ||
960 | break; | ||
961 | case SLIDER_MAX_MOTOR_FORCE: | ||
962 | switch (linAng) | ||
963 | { | ||
964 | case SLIDER_LINEAR: | ||
965 | constraint.SetMaxLinMotorForce(val); | ||
966 | break; | ||
967 | case SLIDER_ANGULAR: | ||
968 | constraint.SetMaxAngMotorForce(val); | ||
969 | break; | ||
970 | } | ||
971 | break; | ||
972 | } | ||
973 | return true; | ||
974 | } | ||
975 | |||
976 | //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); | ||
977 | public override void SetAngularDamping(BulletBody pBody, float angularDamping) | ||
978 | { | ||
979 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
980 | float lineardamping = body.GetLinearDamping(); | ||
981 | body.SetDamping(lineardamping, angularDamping); | ||
982 | |||
983 | } | ||
984 | |||
985 | public override void UpdateInertiaTensor(BulletBody pBody) | ||
986 | { | ||
987 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
988 | if (body != null) // can't update inertia tensor on CollisionObject | ||
989 | body.UpdateInertiaTensor(); | ||
990 | } | ||
991 | |||
992 | public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) | ||
993 | { | ||
994 | CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; | ||
995 | shape.RecalculateLocalAabb(); | ||
996 | } | ||
997 | |||
998 | //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) | ||
999 | public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject) | ||
1000 | { | ||
1001 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1002 | uint flags = (uint)collisionObject.GetCollisionFlags(); | ||
1003 | return (CollisionFlags) flags; | ||
1004 | } | ||
1005 | |||
1006 | public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) | ||
1007 | { | ||
1008 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1009 | body.SetDamping(pLinear, pAngular); | ||
1010 | } | ||
1011 | //PhysBody.ptr, PhysicsScene.Params.deactivationTime); | ||
1012 | public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime) | ||
1013 | { | ||
1014 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1015 | collisionObject.SetDeactivationTime(pDeactivationTime); | ||
1016 | } | ||
1017 | //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | ||
1018 | public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) | ||
1019 | { | ||
1020 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1021 | body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); | ||
1022 | } | ||
1023 | |||
1024 | public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject) | ||
1025 | { | ||
1026 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
1027 | return (CollisionObjectTypes)(int) collisionObject.GetInternalType(); | ||
1028 | } | ||
1029 | |||
1030 | public override void ApplyGravity(BulletBody pBody) | ||
1031 | { | ||
1032 | |||
1033 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1034 | body.ApplyGravity(); | ||
1035 | } | ||
1036 | |||
1037 | public override Vector3 GetGravity(BulletBody pBody) | ||
1038 | { | ||
1039 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1040 | IndexedVector3 gravity = body.GetGravity(); | ||
1041 | return new Vector3(gravity.X, gravity.Y, gravity.Z); | ||
1042 | } | ||
1043 | |||
1044 | public override void SetLinearDamping(BulletBody pBody, float lin_damping) | ||
1045 | { | ||
1046 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1047 | float angularDamping = body.GetAngularDamping(); | ||
1048 | body.SetDamping(lin_damping, angularDamping); | ||
1049 | } | ||
1050 | |||
1051 | public override float GetLinearDamping(BulletBody pBody) | ||
1052 | { | ||
1053 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1054 | return body.GetLinearDamping(); | ||
1055 | } | ||
1056 | |||
1057 | public override float GetAngularDamping(BulletBody pBody) | ||
1058 | { | ||
1059 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1060 | return body.GetAngularDamping(); | ||
1061 | } | ||
1062 | |||
1063 | public override float GetLinearSleepingThreshold(BulletBody pBody) | ||
1064 | { | ||
1065 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1066 | return body.GetLinearSleepingThreshold(); | ||
1067 | } | ||
1068 | |||
1069 | public override void ApplyDamping(BulletBody pBody, float timeStep) | ||
1070 | { | ||
1071 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1072 | body.ApplyDamping(timeStep); | ||
1073 | } | ||
1074 | |||
1075 | public override Vector3 GetLinearFactor(BulletBody pBody) | ||
1076 | { | ||
1077 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1078 | IndexedVector3 linearFactor = body.GetLinearFactor(); | ||
1079 | return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z); | ||
1080 | } | ||
1081 | |||
1082 | public override void SetLinearFactor(BulletBody pBody, Vector3 factor) | ||
1083 | { | ||
1084 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1085 | body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z)); | ||
1086 | } | ||
1087 | |||
1088 | public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot) | ||
1089 | { | ||
1090 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1091 | IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W); | ||
1092 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat); | ||
1093 | mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
1094 | body.SetCenterOfMassTransform( ref mat); | ||
1095 | /* TODO: double check this */ | ||
1096 | } | ||
1097 | |||
1098 | //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); | ||
1099 | public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) | ||
1100 | { | ||
1101 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1102 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
1103 | body.ApplyCentralForce(ref fSum); | ||
1104 | } | ||
1105 | public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) | ||
1106 | { | ||
1107 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1108 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
1109 | body.ApplyCentralImpulse(ref fSum); | ||
1110 | } | ||
1111 | public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) | ||
1112 | { | ||
1113 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1114 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
1115 | body.ApplyTorque(ref fSum); | ||
1116 | } | ||
1117 | public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) | ||
1118 | { | ||
1119 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
1120 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
1121 | body.ApplyTorqueImpulse(ref fSum); | ||
1122 | } | ||
1123 | |||
1124 | public override void DestroyObject(BulletWorld pWorld, BulletBody pBody) | ||
1125 | { | ||
1126 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1127 | CollisionObject co = (pBody as BulletBodyXNA).rigidBody; | ||
1128 | RigidBody bo = co as RigidBody; | ||
1129 | if (bo == null) | ||
1130 | { | ||
1131 | |||
1132 | if (world.IsInWorld(co)) | ||
1133 | { | ||
1134 | world.RemoveCollisionObject(co); | ||
1135 | } | ||
1136 | } | ||
1137 | else | ||
1138 | { | ||
1139 | |||
1140 | if (world.IsInWorld(bo)) | ||
1141 | { | ||
1142 | world.RemoveRigidBody(bo); | ||
1143 | } | ||
1144 | } | ||
1145 | if (co != null) | ||
1146 | { | ||
1147 | if (co.GetUserPointer() != null) | ||
1148 | { | ||
1149 | uint localId = (uint) co.GetUserPointer(); | ||
1150 | if (specialCollisionObjects.ContainsKey(localId)) | ||
1151 | { | ||
1152 | specialCollisionObjects.Remove(localId); | ||
1153 | } | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1157 | } | ||
1158 | |||
1159 | public override void Shutdown(BulletWorld pWorld) | ||
1160 | { | ||
1161 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1162 | world.Cleanup(); | ||
1163 | } | ||
1164 | |||
1165 | public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id) | ||
1166 | { | ||
1167 | CollisionShape shape1 = (pShape as BulletShapeXNA).shape; | ||
1168 | |||
1169 | // TODO: Turn this from a reference copy to a Value Copy. | ||
1170 | BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); | ||
1171 | |||
1172 | return shape2; | ||
1173 | } | ||
1174 | |||
1175 | public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape) | ||
1176 | { | ||
1177 | //TODO: | ||
1178 | return false; | ||
1179 | } | ||
1180 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
1181 | |||
1182 | public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
1183 | { | ||
1184 | CollisionWorld world = (pWorld as BulletWorldXNA).world; | ||
1185 | IndexedMatrix mat = | ||
1186 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | ||
1187 | pRawOrientation.Z, pRawOrientation.W)); | ||
1188 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
1189 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1190 | //UpdateSingleAabb(world, shape); | ||
1191 | // TODO: Feed Update array into null | ||
1192 | SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null); | ||
1193 | RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero); | ||
1194 | RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero) | ||
1195 | { | ||
1196 | m_mass = 0 | ||
1197 | }; | ||
1198 | /* | ||
1199 | m_mass = mass; | ||
1200 | m_motionState =motionState; | ||
1201 | m_collisionShape = collisionShape; | ||
1202 | m_localInertia = localInertia; | ||
1203 | m_linearDamping = 0f; | ||
1204 | m_angularDamping = 0f; | ||
1205 | m_friction = 0.5f; | ||
1206 | m_restitution = 0f; | ||
1207 | m_linearSleepingThreshold = 0.8f; | ||
1208 | m_angularSleepingThreshold = 1f; | ||
1209 | m_additionalDamping = false; | ||
1210 | m_additionalDampingFactor = 0.005f; | ||
1211 | m_additionalLinearDampingThresholdSqr = 0.01f; | ||
1212 | m_additionalAngularDampingThresholdSqr = 0.01f; | ||
1213 | m_additionalAngularDampingFactor = 0.01f; | ||
1214 | m_startWorldTransform = IndexedMatrix.Identity; | ||
1215 | */ | ||
1216 | body.SetUserPointer(pLocalID); | ||
1217 | |||
1218 | return new BulletBodyXNA(pLocalID, body); | ||
1219 | } | ||
1220 | |||
1221 | |||
1222 | public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
1223 | { | ||
1224 | |||
1225 | IndexedMatrix mat = | ||
1226 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | ||
1227 | pRawOrientation.Z, pRawOrientation.W)); | ||
1228 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
1229 | |||
1230 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1231 | |||
1232 | // TODO: Feed Update array into null | ||
1233 | RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); | ||
1234 | body.SetWorldTransform(mat); | ||
1235 | body.SetUserPointer(pLocalID); | ||
1236 | return new BulletBodyXNA(pLocalID, body); | ||
1237 | } | ||
1238 | //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
1239 | public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags) | ||
1240 | { | ||
1241 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1242 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); | ||
1243 | return (CollisionFlags)collisionObject.GetCollisionFlags(); | ||
1244 | } | ||
1245 | |||
1246 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) | ||
1247 | { | ||
1248 | |||
1249 | /* TODO */ | ||
1250 | return Vector3.Zero; | ||
1251 | } | ||
1252 | public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } | ||
1253 | public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } | ||
1254 | public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } | ||
1255 | public override bool IsStaticObject(BulletBody pCollisionObject) | ||
1256 | { | ||
1257 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1258 | return collisionObject.IsStaticObject(); | ||
1259 | |||
1260 | } | ||
1261 | public override bool IsKinematicObject(BulletBody pCollisionObject) | ||
1262 | { | ||
1263 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1264 | return collisionObject.IsKinematicObject(); | ||
1265 | } | ||
1266 | public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject) | ||
1267 | { | ||
1268 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1269 | return collisionObject.IsStaticOrKinematicObject(); | ||
1270 | } | ||
1271 | public override bool HasContactResponse(BulletBody pCollisionObject) | ||
1272 | { | ||
1273 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1274 | return collisionObject.HasContactResponse(); | ||
1275 | } | ||
1276 | public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } | ||
1277 | public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } | ||
1278 | public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } | ||
1279 | public override bool IsActive(BulletBody pBody) { /* TODO */ return false; } | ||
1280 | public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; } | ||
1281 | public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; } | ||
1282 | public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ } | ||
1283 | public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } | ||
1284 | |||
1285 | //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | ||
1286 | public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction) | ||
1287 | { | ||
1288 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1289 | collisionObject.SetHitFraction(pHitFraction); | ||
1290 | } | ||
1291 | //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); | ||
1292 | public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) | ||
1293 | { | ||
1294 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1295 | IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | ||
1296 | CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); | ||
1297 | capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1298 | capsuleShapeZ.SetLocalScaling(ref scale); | ||
1299 | |||
1300 | return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ; | ||
1301 | } | ||
1302 | |||
1303 | public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | ||
1304 | int maxCollisions, ref CollisionDesc[] collisionArray, | ||
1305 | int maxUpdates, ref EntityProperties[] updateArray | ||
1306 | ) | ||
1307 | { | ||
1308 | |||
1309 | UpdatedObjects = updateArray; | ||
1310 | UpdatedCollisions = collisionArray; | ||
1311 | /* TODO */ | ||
1312 | ConfigurationParameters[] configparms = new ConfigurationParameters[1]; | ||
1313 | configparms[0] = parms; | ||
1314 | Vector3 worldExtent = maxPosition; | ||
1315 | m_maxCollisions = maxCollisions; | ||
1316 | m_maxUpdatesPerFrame = maxUpdates; | ||
1317 | specialCollisionObjects = new Dictionary<uint, GhostObject>(); | ||
1318 | |||
1319 | return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); | ||
1320 | } | ||
1321 | |||
1322 | private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, | ||
1323 | ConfigurationParameters[] o, | ||
1324 | int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, | ||
1325 | int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, | ||
1326 | object mDebugLogCallbackHandle) | ||
1327 | { | ||
1328 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); | ||
1329 | |||
1330 | p.angularDamping = BSParam.AngularDamping; | ||
1331 | p.defaultFriction = o[0].defaultFriction; | ||
1332 | p.defaultFriction = o[0].defaultFriction; | ||
1333 | p.defaultDensity = o[0].defaultDensity; | ||
1334 | p.defaultRestitution = o[0].defaultRestitution; | ||
1335 | p.collisionMargin = o[0].collisionMargin; | ||
1336 | p.gravity = o[0].gravity; | ||
1337 | |||
1338 | p.linearDamping = BSParam.LinearDamping; | ||
1339 | p.angularDamping = BSParam.AngularDamping; | ||
1340 | p.deactivationTime = BSParam.DeactivationTime; | ||
1341 | p.linearSleepingThreshold = BSParam.LinearSleepingThreshold; | ||
1342 | p.angularSleepingThreshold = BSParam.AngularSleepingThreshold; | ||
1343 | p.ccdMotionThreshold = BSParam.CcdMotionThreshold; | ||
1344 | p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius; | ||
1345 | p.contactProcessingThreshold = BSParam.ContactProcessingThreshold; | ||
1346 | |||
1347 | p.terrainImplementation = BSParam.TerrainImplementation; | ||
1348 | p.terrainFriction = BSParam.TerrainFriction; | ||
1349 | |||
1350 | p.terrainHitFraction = BSParam.TerrainHitFraction; | ||
1351 | p.terrainRestitution = BSParam.TerrainRestitution; | ||
1352 | p.terrainCollisionMargin = BSParam.TerrainCollisionMargin; | ||
1353 | |||
1354 | p.avatarFriction = BSParam.AvatarFriction; | ||
1355 | p.avatarStandingFriction = BSParam.AvatarStandingFriction; | ||
1356 | p.avatarDensity = BSParam.AvatarDensity; | ||
1357 | p.avatarRestitution = BSParam.AvatarRestitution; | ||
1358 | p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth; | ||
1359 | p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; | ||
1360 | p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; | ||
1361 | p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; | ||
1362 | |||
1363 | p.vehicleAngularDamping = BSParam.VehicleAngularDamping; | ||
1364 | |||
1365 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; | ||
1366 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; | ||
1367 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; | ||
1368 | p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; | ||
1369 | p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; | ||
1370 | p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; | ||
1371 | p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; | ||
1372 | p.numberOfSolverIterations = o[0].numberOfSolverIterations; | ||
1373 | |||
1374 | p.linksetImplementation = BSParam.LinksetImplementation; | ||
1375 | p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset); | ||
1376 | p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor); | ||
1377 | p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; | ||
1378 | p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; | ||
1379 | p.linkConstraintERP = BSParam.LinkConstraintERP; | ||
1380 | p.linkConstraintCFM = BSParam.LinkConstraintCFM; | ||
1381 | p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; | ||
1382 | p.physicsLoggingFrames = o[0].physicsLoggingFrames; | ||
1383 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); | ||
1384 | |||
1385 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); | ||
1386 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); | ||
1387 | |||
1388 | |||
1389 | if (p.maxPersistantManifoldPoolSize > 0) | ||
1390 | cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; | ||
1391 | if (p.shouldDisableContactPoolDynamicAllocation !=0) | ||
1392 | m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); | ||
1393 | //if (p.maxCollisionAlgorithmPoolSize >0 ) | ||
1394 | |||
1395 | DbvtBroadphase m_broadphase = new DbvtBroadphase(); | ||
1396 | //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); | ||
1397 | //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); | ||
1398 | |||
1399 | //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); | ||
1400 | m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); | ||
1401 | |||
1402 | SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); | ||
1403 | |||
1404 | DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); | ||
1405 | |||
1406 | world.LastCollisionDesc = 0; | ||
1407 | world.LastEntityProperty = 0; | ||
1408 | |||
1409 | world.WorldSettings.Params = p; | ||
1410 | world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); | ||
1411 | world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; | ||
1412 | if (p.shouldRandomizeSolverOrder != 0) | ||
1413 | world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; | ||
1414 | |||
1415 | world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); | ||
1416 | //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port | ||
1417 | |||
1418 | if (p.shouldEnableFrictionCaching != 0) | ||
1419 | world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; | ||
1420 | |||
1421 | if (p.numberOfSolverIterations > 0) | ||
1422 | world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; | ||
1423 | |||
1424 | |||
1425 | world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; | ||
1426 | world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; | ||
1427 | world.GetSolverInfo().m_globalCfm = 0.0f; | ||
1428 | world.GetSolverInfo().m_tau = 0.6f; | ||
1429 | world.GetSolverInfo().m_friction = 0.3f; | ||
1430 | world.GetSolverInfo().m_maxErrorReduction = 20f; | ||
1431 | world.GetSolverInfo().m_numIterations = 10; | ||
1432 | world.GetSolverInfo().m_erp = 0.2f; | ||
1433 | world.GetSolverInfo().m_erp2 = 0.1f; | ||
1434 | world.GetSolverInfo().m_sor = 1.0f; | ||
1435 | world.GetSolverInfo().m_splitImpulse = false; | ||
1436 | world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; | ||
1437 | world.GetSolverInfo().m_linearSlop = 0.0f; | ||
1438 | world.GetSolverInfo().m_warmstartingFactor = 0.85f; | ||
1439 | world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; | ||
1440 | world.SetForceUpdateAllAabbs(true); | ||
1441 | |||
1442 | //BSParam.TerrainImplementation = 0; | ||
1443 | world.SetGravity(new IndexedVector3(0,0,p.gravity)); | ||
1444 | |||
1445 | // Turn off Pooling since globals and pooling are bad for threading. | ||
1446 | BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false); | ||
1447 | BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false); | ||
1448 | BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false); | ||
1449 | BulletGlobals.CastResultPool.SetPoolingEnabled(false); | ||
1450 | BulletGlobals.SphereShapePool.SetPoolingEnabled(false); | ||
1451 | BulletGlobals.DbvtNodePool.SetPoolingEnabled(false); | ||
1452 | BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false); | ||
1453 | BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false); | ||
1454 | BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false); | ||
1455 | BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false); | ||
1456 | BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false); | ||
1457 | BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false); | ||
1458 | BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false); | ||
1459 | BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false); | ||
1460 | BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false); | ||
1461 | BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false); | ||
1462 | |||
1463 | BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1464 | BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1465 | BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1466 | BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false); | ||
1467 | BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false); | ||
1468 | BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1469 | BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1470 | BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1471 | BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1472 | BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false); | ||
1473 | BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false); | ||
1474 | BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false); | ||
1475 | BulletGlobals.GJKPool.SetPoolingEnabled(false); | ||
1476 | BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false); | ||
1477 | BulletGlobals.TriangleShapePool.SetPoolingEnabled(false); | ||
1478 | BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false); | ||
1479 | BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false); | ||
1480 | BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false); | ||
1481 | BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false); | ||
1482 | BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false); | ||
1483 | BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false); | ||
1484 | BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false); | ||
1485 | BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false); | ||
1486 | BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false); | ||
1487 | BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false); | ||
1488 | |||
1489 | return world; | ||
1490 | } | ||
1491 | //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL | ||
1492 | public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) | ||
1493 | { | ||
1494 | Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; | ||
1495 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | ||
1496 | { | ||
1497 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); | ||
1498 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); | ||
1499 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); | ||
1500 | } | ||
1501 | if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | ||
1502 | { | ||
1503 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); | ||
1504 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); | ||
1505 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); | ||
1506 | } | ||
1507 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) | ||
1508 | { | ||
1509 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); | ||
1510 | } | ||
1511 | return true; | ||
1512 | } | ||
1513 | |||
1514 | public override bool PushUpdate(BulletBody pCollisionObject) | ||
1515 | { | ||
1516 | bool ret = false; | ||
1517 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1518 | RigidBody rb = collisionObject as RigidBody; | ||
1519 | if (rb != null) | ||
1520 | { | ||
1521 | SimMotionState sms = rb.GetMotionState() as SimMotionState; | ||
1522 | if (sms != null) | ||
1523 | { | ||
1524 | IndexedMatrix wt = IndexedMatrix.Identity; | ||
1525 | sms.GetWorldTransform(out wt); | ||
1526 | sms.SetWorldTransform(ref wt, true); | ||
1527 | ret = true; | ||
1528 | } | ||
1529 | } | ||
1530 | return ret; | ||
1531 | |||
1532 | } | ||
1533 | |||
1534 | public override float GetAngularMotionDisc(BulletShape pShape) | ||
1535 | { | ||
1536 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1537 | return shape.GetAngularMotionDisc(); | ||
1538 | } | ||
1539 | public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) | ||
1540 | { | ||
1541 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1542 | return shape.GetContactBreakingThreshold(defaultFactor); | ||
1543 | } | ||
1544 | public override bool IsCompound(BulletShape pShape) | ||
1545 | { | ||
1546 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1547 | return shape.IsCompound(); | ||
1548 | } | ||
1549 | public override bool IsSoftBody(BulletShape pShape) | ||
1550 | { | ||
1551 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1552 | return shape.IsSoftBody(); | ||
1553 | } | ||
1554 | public override bool IsPolyhedral(BulletShape pShape) | ||
1555 | { | ||
1556 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1557 | return shape.IsPolyhedral(); | ||
1558 | } | ||
1559 | public override bool IsConvex2d(BulletShape pShape) | ||
1560 | { | ||
1561 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1562 | return shape.IsConvex2d(); | ||
1563 | } | ||
1564 | public override bool IsConvex(BulletShape pShape) | ||
1565 | { | ||
1566 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1567 | return shape.IsConvex(); | ||
1568 | } | ||
1569 | public override bool IsNonMoving(BulletShape pShape) | ||
1570 | { | ||
1571 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1572 | return shape.IsNonMoving(); | ||
1573 | } | ||
1574 | public override bool IsConcave(BulletShape pShape) | ||
1575 | { | ||
1576 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1577 | return shape.IsConcave(); | ||
1578 | } | ||
1579 | public override bool IsInfinite(BulletShape pShape) | ||
1580 | { | ||
1581 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1582 | return shape.IsInfinite(); | ||
1583 | } | ||
1584 | public override bool IsNativeShape(BulletShape pShape) | ||
1585 | { | ||
1586 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1587 | bool ret; | ||
1588 | switch (shape.GetShapeType()) | ||
1589 | { | ||
1590 | case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: | ||
1591 | case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: | ||
1592 | case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: | ||
1593 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | ||
1594 | ret = true; | ||
1595 | break; | ||
1596 | default: | ||
1597 | ret = false; | ||
1598 | break; | ||
1599 | } | ||
1600 | return ret; | ||
1601 | } | ||
1602 | |||
1603 | public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin) | ||
1604 | { | ||
1605 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1606 | shape.SetMargin(pMargin); | ||
1607 | } | ||
1608 | |||
1609 | //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation | ||
1610 | public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
1611 | { | ||
1612 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1613 | IndexedMatrix bodyTransform = new IndexedMatrix(); | ||
1614 | bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
1615 | bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); | ||
1616 | GhostObject gObj = new PairCachingGhostObject(); | ||
1617 | gObj.SetWorldTransform(bodyTransform); | ||
1618 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1619 | gObj.SetCollisionShape(shape); | ||
1620 | gObj.SetUserPointer(pLocalID); | ||
1621 | |||
1622 | if (specialCollisionObjects.ContainsKey(pLocalID)) | ||
1623 | specialCollisionObjects[pLocalID] = gObj; | ||
1624 | else | ||
1625 | specialCollisionObjects.Add(pLocalID, gObj); | ||
1626 | |||
1627 | // TODO: Add to Special CollisionObjects! | ||
1628 | return new BulletBodyXNA(pLocalID, gObj); | ||
1629 | } | ||
1630 | |||
1631 | public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape) | ||
1632 | { | ||
1633 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1634 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
1635 | if (pShape == null) | ||
1636 | { | ||
1637 | collisionObject.SetCollisionShape(new EmptyShape()); | ||
1638 | } | ||
1639 | else | ||
1640 | { | ||
1641 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1642 | collisionObject.SetCollisionShape(shape); | ||
1643 | } | ||
1644 | } | ||
1645 | public override BulletShape GetCollisionShape(BulletBody pCollisionObject) | ||
1646 | { | ||
1647 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1648 | CollisionShape shape = collisionObject.GetCollisionShape(); | ||
1649 | return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | ||
1650 | } | ||
1651 | |||
1652 | //(PhysicsScene.World.ptr, nativeShapeData) | ||
1653 | public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) | ||
1654 | { | ||
1655 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1656 | CollisionShape shape = null; | ||
1657 | switch (pShapeData.Type) | ||
1658 | { | ||
1659 | case BSPhysicsShapeType.SHAPE_BOX: | ||
1660 | shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); | ||
1661 | break; | ||
1662 | case BSPhysicsShapeType.SHAPE_CONE: | ||
1663 | shape = new ConeShapeZ(0.5f, 1.0f); | ||
1664 | break; | ||
1665 | case BSPhysicsShapeType.SHAPE_CYLINDER: | ||
1666 | shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); | ||
1667 | break; | ||
1668 | case BSPhysicsShapeType.SHAPE_SPHERE: | ||
1669 | shape = new SphereShape(0.5f); | ||
1670 | break; | ||
1671 | |||
1672 | } | ||
1673 | if (shape != null) | ||
1674 | { | ||
1675 | IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); | ||
1676 | shape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1677 | shape.SetLocalScaling(ref scaling); | ||
1678 | |||
1679 | } | ||
1680 | return new BulletShapeXNA(shape, pShapeData.Type); | ||
1681 | } | ||
1682 | //PhysicsScene.World.ptr, false | ||
1683 | public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree) | ||
1684 | { | ||
1685 | return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND); | ||
1686 | } | ||
1687 | |||
1688 | public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) | ||
1689 | { | ||
1690 | CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; | ||
1691 | return compoundshape.GetNumChildShapes(); | ||
1692 | } | ||
1693 | //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot | ||
1694 | public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) | ||
1695 | { | ||
1696 | IndexedMatrix relativeTransform = new IndexedMatrix(); | ||
1697 | CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; | ||
1698 | CollisionShape addshape = (paddShape as BulletShapeXNA).shape; | ||
1699 | |||
1700 | relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); | ||
1701 | relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); | ||
1702 | compoundshape.AddChildShape(ref relativeTransform, addshape); | ||
1703 | |||
1704 | } | ||
1705 | |||
1706 | public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) | ||
1707 | { | ||
1708 | CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; | ||
1709 | CollisionShape ret = null; | ||
1710 | ret = compoundshape.GetChildShape(pii); | ||
1711 | compoundshape.RemoveChildShapeByIndex(pii); | ||
1712 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); | ||
1713 | } | ||
1714 | |||
1715 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { | ||
1716 | |||
1717 | if (cShape == null) | ||
1718 | return null; | ||
1719 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; | ||
1720 | CollisionShape shape = compoundShape.GetChildShape(indx); | ||
1721 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | ||
1722 | |||
1723 | |||
1724 | return retShape; | ||
1725 | } | ||
1726 | |||
1727 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) | ||
1728 | { | ||
1729 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1730 | switch (pin) | ||
1731 | { | ||
1732 | case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: | ||
1733 | ret = BSPhysicsShapeType.SHAPE_BOX; | ||
1734 | break; | ||
1735 | case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE: | ||
1736 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1737 | break; | ||
1738 | |||
1739 | case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE: | ||
1740 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1741 | break; | ||
1742 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: | ||
1743 | ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; | ||
1744 | break; | ||
1745 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: | ||
1746 | ret = BSPhysicsShapeType.SHAPE_HULL; | ||
1747 | break; | ||
1748 | case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | ||
1749 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1750 | break; | ||
1751 | case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE: | ||
1752 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1753 | break; | ||
1754 | //implicit convex shapes | ||
1755 | case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE: | ||
1756 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1757 | break; | ||
1758 | case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: | ||
1759 | ret = BSPhysicsShapeType.SHAPE_SPHERE; | ||
1760 | break; | ||
1761 | case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE: | ||
1762 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1763 | break; | ||
1764 | case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE: | ||
1765 | ret = BSPhysicsShapeType.SHAPE_CAPSULE; | ||
1766 | break; | ||
1767 | case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: | ||
1768 | ret = BSPhysicsShapeType.SHAPE_CONE; | ||
1769 | break; | ||
1770 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: | ||
1771 | ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; | ||
1772 | break; | ||
1773 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | ||
1774 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; | ||
1775 | break; | ||
1776 | case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE: | ||
1777 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1778 | break; | ||
1779 | case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE: | ||
1780 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1781 | break; | ||
1782 | case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE: | ||
1783 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1784 | break; | ||
1785 | case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE: | ||
1786 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1787 | break; | ||
1788 | case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE: | ||
1789 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1790 | break; | ||
1791 | case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE: | ||
1792 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1793 | break; | ||
1794 | //concave shape | ||
1795 | case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE: | ||
1796 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1797 | break; | ||
1798 | //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! | ||
1799 | case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE: | ||
1800 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1801 | break; | ||
1802 | case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE: | ||
1803 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1804 | break; | ||
1805 | ///used for demo integration FAST/Swift collision library and Bullet | ||
1806 | case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE: | ||
1807 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1808 | break; | ||
1809 | //terrain | ||
1810 | case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE: | ||
1811 | ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP; | ||
1812 | break; | ||
1813 | ///Used for GIMPACT Trimesh integration | ||
1814 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: | ||
1815 | ret = BSPhysicsShapeType.SHAPE_GIMPACT; | ||
1816 | break; | ||
1817 | ///Multimaterial mesh | ||
1818 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: | ||
1819 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1820 | break; | ||
1821 | |||
1822 | case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE: | ||
1823 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1824 | break; | ||
1825 | case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE: | ||
1826 | ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE; | ||
1827 | break; | ||
1828 | case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE: | ||
1829 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1830 | break; | ||
1831 | case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE: | ||
1832 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1833 | break; | ||
1834 | |||
1835 | case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE: | ||
1836 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
1837 | break; | ||
1838 | |||
1839 | case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE: | ||
1840 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1841 | break; | ||
1842 | case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE: | ||
1843 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1844 | break; | ||
1845 | case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE: | ||
1846 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1847 | break; | ||
1848 | case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE: | ||
1849 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1850 | break; | ||
1851 | } | ||
1852 | return ret; | ||
1853 | } | ||
1854 | |||
1855 | public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } | ||
1856 | public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ } | ||
1857 | |||
1858 | public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) | ||
1859 | { | ||
1860 | StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); | ||
1861 | m_planeshape.SetMargin(pcollisionMargin); | ||
1862 | m_planeshape.SetUserPointer(pLocalId); | ||
1863 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); | ||
1864 | } | ||
1865 | |||
1866 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1867 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | ||
1868 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1869 | |||
1870 | { | ||
1871 | Generic6DofSpringConstraint constrain = null; | ||
1872 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1873 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1874 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1875 | if (body1 != null && body2 != null) | ||
1876 | { | ||
1877 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1878 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1879 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1880 | frame1._origin = frame1v; | ||
1881 | |||
1882 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1883 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1884 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1885 | frame2._origin = frame1v; | ||
1886 | |||
1887 | constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
1888 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1889 | |||
1890 | constrain.CalculateTransforms(); | ||
1891 | } | ||
1892 | |||
1893 | return new BulletConstraintXNA(constrain); | ||
1894 | } | ||
1895 | |||
1896 | public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1897 | Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, | ||
1898 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1899 | { | ||
1900 | HingeConstraint constrain = null; | ||
1901 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1902 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1903 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1904 | if (rb1 != null && rb2 != null) | ||
1905 | { | ||
1906 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); | ||
1907 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); | ||
1908 | IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); | ||
1909 | IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); | ||
1910 | constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA); | ||
1911 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1912 | } | ||
1913 | return new BulletConstraintXNA(constrain); | ||
1914 | } | ||
1915 | |||
1916 | public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1917 | Vector3 pframe1, Quaternion pframe1rot, | ||
1918 | Vector3 pframe2, Quaternion pframe2rot, | ||
1919 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1920 | { | ||
1921 | SliderConstraint constrain = null; | ||
1922 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1923 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1924 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1925 | if (rb1 != null && rb2 != null) | ||
1926 | { | ||
1927 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1928 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1929 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1930 | frame1._origin = frame1v; | ||
1931 | |||
1932 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1933 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1934 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1935 | frame2._origin = frame1v; | ||
1936 | |||
1937 | constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
1938 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1939 | } | ||
1940 | return new BulletConstraintXNA(constrain); | ||
1941 | } | ||
1942 | |||
1943 | public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1944 | Vector3 pframe1, Quaternion pframe1rot, | ||
1945 | Vector3 pframe2, Quaternion pframe2rot, | ||
1946 | bool pdisableCollisionsBetweenLinkedBodies) | ||
1947 | { | ||
1948 | ConeTwistConstraint constrain = null; | ||
1949 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1950 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1951 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1952 | if (rb1 != null && rb2 != null) | ||
1953 | { | ||
1954 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1955 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1956 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1957 | frame1._origin = frame1v; | ||
1958 | |||
1959 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1960 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1961 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1962 | frame2._origin = frame1v; | ||
1963 | |||
1964 | constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2); | ||
1965 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1966 | } | ||
1967 | return new BulletConstraintXNA(constrain); | ||
1968 | } | ||
1969 | |||
1970 | public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1971 | Vector3 paxisInA, Vector3 paxisInB, | ||
1972 | float pratio, bool pdisableCollisionsBetweenLinkedBodies) | ||
1973 | { | ||
1974 | Generic6DofConstraint constrain = null; | ||
1975 | /* BulletXNA does not have a gear constraint | ||
1976 | GearConstraint constrain = null; | ||
1977 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1978 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1979 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1980 | if (rb1 != null && rb2 != null) | ||
1981 | { | ||
1982 | IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); | ||
1983 | IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); | ||
1984 | constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio); | ||
1985 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1986 | } | ||
1987 | */ | ||
1988 | return new BulletConstraintXNA(constrain); | ||
1989 | } | ||
1990 | |||
1991 | public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1992 | Vector3 ppivotInA, Vector3 ppivotInB, | ||
1993 | bool pdisableCollisionsBetweenLinkedBodies) | ||
1994 | { | ||
1995 | Point2PointConstraint constrain = null; | ||
1996 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1997 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1998 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1999 | if (rb1 != null && rb2 != null) | ||
2000 | { | ||
2001 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); | ||
2002 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); | ||
2003 | constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB); | ||
2004 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
2005 | } | ||
2006 | return new BulletConstraintXNA(constrain); | ||
2007 | } | ||
2008 | |||
2009 | public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) | ||
2010 | { | ||
2011 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
2012 | CompoundShape compoundshape = new CompoundShape(false); | ||
2013 | |||
2014 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
2015 | int ii = 1; | ||
2016 | |||
2017 | for (int i = 0; i < pHullCount; i++) | ||
2018 | { | ||
2019 | int vertexCount = (int) pConvHulls[ii]; | ||
2020 | |||
2021 | IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); | ||
2022 | IndexedMatrix childTrans = IndexedMatrix.Identity; | ||
2023 | childTrans._origin = centroid; | ||
2024 | |||
2025 | List<IndexedVector3> virts = new List<IndexedVector3>(); | ||
2026 | int ender = ((ii + 4) + (vertexCount*3)); | ||
2027 | for (int iii = ii + 4; iii < ender; iii+=3) | ||
2028 | { | ||
2029 | |||
2030 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); | ||
2031 | } | ||
2032 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); | ||
2033 | convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
2034 | compoundshape.AddChildShape(ref childTrans, convexShape); | ||
2035 | ii += (vertexCount*3 + 4); | ||
2036 | } | ||
2037 | |||
2038 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); | ||
2039 | } | ||
2040 | |||
2041 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) | ||
2042 | { | ||
2043 | /* TODO */ return null; | ||
2044 | } | ||
2045 | |||
2046 | public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
2047 | { | ||
2048 | /* TODO */ return null; | ||
2049 | } | ||
2050 | |||
2051 | public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
2052 | { | ||
2053 | /* TODO */ return null; | ||
2054 | } | ||
2055 | |||
2056 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
2057 | { | ||
2058 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); | ||
2059 | |||
2060 | for (int iter = 0; iter < pVerticesCount; iter++) | ||
2061 | { | ||
2062 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; | ||
2063 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; | ||
2064 | } | ||
2065 | |||
2066 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); | ||
2067 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); | ||
2068 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); | ||
2069 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
2070 | IndexedMesh mesh = new IndexedMesh(); | ||
2071 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
2072 | mesh.m_numTriangles = pIndicesCount/3; | ||
2073 | mesh.m_numVertices = pVerticesCount; | ||
2074 | mesh.m_triangleIndexBase = indicesarr; | ||
2075 | mesh.m_vertexBase = vertices; | ||
2076 | mesh.m_vertexStride = 3; | ||
2077 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
2078 | mesh.m_triangleIndexStride = 3; | ||
2079 | |||
2080 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
2081 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
2082 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); | ||
2083 | meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
2084 | // world.UpdateSingleAabb(meshShape); | ||
2085 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); | ||
2086 | |||
2087 | } | ||
2088 | public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
2089 | { | ||
2090 | // TODO: | ||
2091 | return null; | ||
2092 | } | ||
2093 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) | ||
2094 | { | ||
2095 | |||
2096 | String fileName = "objTest3.raw"; | ||
2097 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | ||
2098 | StreamWriter sw = new StreamWriter(completePath); | ||
2099 | IndexedMesh mesh = new IndexedMesh(); | ||
2100 | |||
2101 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
2102 | mesh.m_numTriangles = pIndicesCount / 3; | ||
2103 | mesh.m_numVertices = pVerticesCount; | ||
2104 | mesh.m_triangleIndexBase = indices; | ||
2105 | mesh.m_vertexBase = vertices; | ||
2106 | mesh.m_vertexStride = 3; | ||
2107 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
2108 | mesh.m_triangleIndexStride = 3; | ||
2109 | |||
2110 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
2111 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
2112 | |||
2113 | |||
2114 | |||
2115 | for (int i = 0; i < pVerticesCount; i++) | ||
2116 | { | ||
2117 | |||
2118 | string s = vertices[indices[i * 3]].ToString("0.0000"); | ||
2119 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | ||
2120 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | ||
2121 | |||
2122 | sw.Write(s + "\n"); | ||
2123 | } | ||
2124 | |||
2125 | sw.Close(); | ||
2126 | } | ||
2127 | public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) | ||
2128 | { | ||
2129 | |||
2130 | String fileName = "objTest6.raw"; | ||
2131 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | ||
2132 | StreamWriter sw = new StreamWriter(completePath); | ||
2133 | IndexedMesh mesh = new IndexedMesh(); | ||
2134 | |||
2135 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
2136 | mesh.m_numTriangles = pIndicesCount / 3; | ||
2137 | mesh.m_numVertices = pVerticesCount; | ||
2138 | mesh.m_triangleIndexBase = indices; | ||
2139 | mesh.m_vertexBase = vertices; | ||
2140 | mesh.m_vertexStride = 3; | ||
2141 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
2142 | mesh.m_triangleIndexStride = 3; | ||
2143 | |||
2144 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
2145 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
2146 | |||
2147 | |||
2148 | sw.WriteLine("Indices"); | ||
2149 | sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); | ||
2150 | for (int iter = 0; iter < indices.Length; iter++) | ||
2151 | { | ||
2152 | sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); | ||
2153 | } | ||
2154 | sw.WriteLine("VerticesFloats"); | ||
2155 | sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); | ||
2156 | for (int iter = 0; iter < vertices.Length; iter++) | ||
2157 | { | ||
2158 | sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); | ||
2159 | } | ||
2160 | |||
2161 | // for (int i = 0; i < pVerticesCount; i++) | ||
2162 | // { | ||
2163 | // | ||
2164 | // string s = vertices[indices[i * 3]].ToString("0.0000"); | ||
2165 | // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | ||
2166 | // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | ||
2167 | // | ||
2168 | // sw.Write(s + "\n"); | ||
2169 | //} | ||
2170 | |||
2171 | sw.Close(); | ||
2172 | } | ||
2173 | |||
2174 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
2175 | float scaleFactor, float collisionMargin) | ||
2176 | { | ||
2177 | const int upAxis = 2; | ||
2178 | HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y, | ||
2179 | heightMap, scaleFactor, | ||
2180 | minHeight, maxHeight, upAxis, | ||
2181 | false); | ||
2182 | terrainShape.SetMargin(collisionMargin); | ||
2183 | terrainShape.SetUseDiamondSubdivision(true); | ||
2184 | terrainShape.SetUserPointer(id); | ||
2185 | return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); | ||
2186 | } | ||
2187 | |||
2188 | public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) | ||
2189 | { | ||
2190 | TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain; | ||
2191 | bool onOff = ponOff != 0; | ||
2192 | bool ret = false; | ||
2193 | |||
2194 | switch (tconstrain.GetConstraintType()) | ||
2195 | { | ||
2196 | case TypedConstraintType.D6_CONSTRAINT_TYPE: | ||
2197 | Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint; | ||
2198 | constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; | ||
2199 | constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; | ||
2200 | constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; | ||
2201 | ret = true; | ||
2202 | break; | ||
2203 | } | ||
2204 | |||
2205 | |||
2206 | return ret; | ||
2207 | |||
2208 | } | ||
2209 | |||
2210 | public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
2211 | out int updatedEntityCount, out int collidersCount) | ||
2212 | { | ||
2213 | /* TODO */ | ||
2214 | updatedEntityCount = 0; | ||
2215 | collidersCount = 0; | ||
2216 | |||
2217 | |||
2218 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); | ||
2219 | |||
2220 | return ret; | ||
2221 | } | ||
2222 | |||
2223 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, | ||
2224 | out int updatedEntityCount, out EntityProperties[] updatedEntities, | ||
2225 | out int collidersCount, out CollisionDesc[] colliders) | ||
2226 | { | ||
2227 | int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, | ||
2228 | out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame); | ||
2229 | return epic; | ||
2230 | } | ||
2231 | |||
2232 | private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, | ||
2233 | out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) | ||
2234 | { | ||
2235 | int numSimSteps = 0; | ||
2236 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); | ||
2237 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); | ||
2238 | LastEntityProperty=0; | ||
2239 | |||
2240 | |||
2241 | |||
2242 | |||
2243 | |||
2244 | |||
2245 | LastCollisionDesc=0; | ||
2246 | |||
2247 | updatedEntityCount = 0; | ||
2248 | collidersCount = 0; | ||
2249 | |||
2250 | |||
2251 | if (pWorld is BulletWorldXNA) | ||
2252 | { | ||
2253 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
2254 | |||
2255 | world.LastCollisionDesc = 0; | ||
2256 | world.LastEntityProperty = 0; | ||
2257 | numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); | ||
2258 | |||
2259 | PersistentManifold contactManifold; | ||
2260 | CollisionObject objA; | ||
2261 | CollisionObject objB; | ||
2262 | ManifoldPoint manifoldPoint; | ||
2263 | PairCachingGhostObject pairCachingGhostObject; | ||
2264 | |||
2265 | m_collisionsThisFrame = 0; | ||
2266 | int numManifolds = world.GetDispatcher().GetNumManifolds(); | ||
2267 | for (int j = 0; j < numManifolds; j++) | ||
2268 | { | ||
2269 | contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); | ||
2270 | int numContacts = contactManifold.GetNumContacts(); | ||
2271 | if (numContacts == 0) | ||
2272 | continue; | ||
2273 | |||
2274 | objA = contactManifold.GetBody0() as CollisionObject; | ||
2275 | objB = contactManifold.GetBody1() as CollisionObject; | ||
2276 | |||
2277 | manifoldPoint = contactManifold.GetContactPoint(0); | ||
2278 | //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); | ||
2279 | // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A | ||
2280 | |||
2281 | RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance()); | ||
2282 | m_collisionsThisFrame ++; | ||
2283 | if (m_collisionsThisFrame >= 9999999) | ||
2284 | break; | ||
2285 | |||
2286 | |||
2287 | } | ||
2288 | |||
2289 | foreach (GhostObject ghostObject in specialCollisionObjects.Values) | ||
2290 | { | ||
2291 | pairCachingGhostObject = ghostObject as PairCachingGhostObject; | ||
2292 | if (pairCachingGhostObject != null) | ||
2293 | { | ||
2294 | RecordGhostCollisions(pairCachingGhostObject); | ||
2295 | } | ||
2296 | |||
2297 | } | ||
2298 | |||
2299 | |||
2300 | updatedEntityCount = LastEntityProperty; | ||
2301 | updatedEntities = UpdatedObjects; | ||
2302 | |||
2303 | collidersCount = LastCollisionDesc; | ||
2304 | colliders = UpdatedCollisions; | ||
2305 | |||
2306 | |||
2307 | } | ||
2308 | else | ||
2309 | { | ||
2310 | //if (updatedEntities is null) | ||
2311 | //updatedEntities = new List<BulletXNA.EntityProperties>(); | ||
2312 | //updatedEntityCount = 0; | ||
2313 | |||
2314 | |||
2315 | //collidersCount = 0; | ||
2316 | |||
2317 | updatedEntities = new EntityProperties[0]; | ||
2318 | |||
2319 | |||
2320 | colliders = new CollisionDesc[0]; | ||
2321 | |||
2322 | } | ||
2323 | return numSimSteps; | ||
2324 | } | ||
2325 | public void RecordGhostCollisions(PairCachingGhostObject obj) | ||
2326 | { | ||
2327 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); | ||
2328 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); | ||
2329 | |||
2330 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; | ||
2331 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); | ||
2332 | BroadphasePair collisionPair; | ||
2333 | PersistentManifold contactManifold; | ||
2334 | |||
2335 | CollisionObject objA; | ||
2336 | CollisionObject objB; | ||
2337 | |||
2338 | ManifoldPoint pt; | ||
2339 | |||
2340 | int numPairs = pairs.Count; | ||
2341 | |||
2342 | for (int i = 0; i < numPairs; i++) | ||
2343 | { | ||
2344 | manifoldArray.Clear(); | ||
2345 | if (LastCollisionDesc < UpdatedCollisions.Length) | ||
2346 | break; | ||
2347 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); | ||
2348 | if (collisionPair == null) | ||
2349 | continue; | ||
2350 | |||
2351 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); | ||
2352 | for (int j = 0; j < manifoldArray.Count; j++) | ||
2353 | { | ||
2354 | contactManifold = manifoldArray[j]; | ||
2355 | int numContacts = contactManifold.GetNumContacts(); | ||
2356 | objA = contactManifold.GetBody0() as CollisionObject; | ||
2357 | objB = contactManifold.GetBody1() as CollisionObject; | ||
2358 | for (int p = 0; p < numContacts; p++) | ||
2359 | { | ||
2360 | pt = contactManifold.GetContactPoint(p); | ||
2361 | if (pt.GetDistance() < 0.0f) | ||
2362 | { | ||
2363 | RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance()); | ||
2364 | break; | ||
2365 | } | ||
2366 | } | ||
2367 | } | ||
2368 | } | ||
2369 | |||
2370 | } | ||
2371 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) | ||
2372 | { | ||
2373 | |||
2374 | IndexedVector3 contactNormal = norm; | ||
2375 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && | ||
2376 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) | ||
2377 | { | ||
2378 | return; | ||
2379 | } | ||
2380 | uint idA = (uint)objA.GetUserPointer(); | ||
2381 | uint idB = (uint)objB.GetUserPointer(); | ||
2382 | if (idA > idB) | ||
2383 | { | ||
2384 | uint temp = idA; | ||
2385 | idA = idB; | ||
2386 | idB = temp; | ||
2387 | contactNormal = -contactNormal; | ||
2388 | } | ||
2389 | |||
2390 | //ulong collisionID = ((ulong) idA << 32) | idB; | ||
2391 | |||
2392 | CollisionDesc cDesc = new CollisionDesc() | ||
2393 | { | ||
2394 | aID = idA, | ||
2395 | bID = idB, | ||
2396 | point = new Vector3(contact.X,contact.Y,contact.Z), | ||
2397 | normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z), | ||
2398 | penetration = penetration | ||
2399 | |||
2400 | }; | ||
2401 | if (world.LastCollisionDesc < world.UpdatedCollisions.Length) | ||
2402 | world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc); | ||
2403 | m_collisionsThisFrame++; | ||
2404 | |||
2405 | |||
2406 | } | ||
2407 | private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject) | ||
2408 | { | ||
2409 | EntityProperties ent = new EntityProperties(); | ||
2410 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
2411 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
2412 | IndexedMatrix transform = collisionObject.GetWorldTransform(); | ||
2413 | IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity(); | ||
2414 | IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity(); | ||
2415 | IndexedQuaternion rotation = transform.GetRotation(); | ||
2416 | ent.Acceleration = Vector3.Zero; | ||
2417 | ent.ID = (uint)collisionObject.GetUserPointer(); | ||
2418 | ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); | ||
2419 | ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); | ||
2420 | ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); | ||
2421 | ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); | ||
2422 | return ent; | ||
2423 | } | ||
2424 | |||
2425 | public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ | ||
2426 | return false; } | ||
2427 | |||
2428 | public override Vector3 GetLocalScaling(BulletShape pShape) | ||
2429 | { | ||
2430 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
2431 | IndexedVector3 scale = shape.GetLocalScaling(); | ||
2432 | return new Vector3(scale.X,scale.Y,scale.Z); | ||
2433 | } | ||
2434 | |||
2435 | public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) | ||
2436 | { | ||
2437 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
2438 | if (world != null) | ||
2439 | { | ||
2440 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) | ||
2441 | { | ||
2442 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; | ||
2443 | |||
2444 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); | ||
2445 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); | ||
2446 | using ( | ||
2447 | ClosestNotMeRayResultCallback rayCallback = | ||
2448 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) | ||
2449 | ) | ||
2450 | { | ||
2451 | world.RayTest(ref rOrigin, ref rEnd, rayCallback); | ||
2452 | if (rayCallback.HasHit()) | ||
2453 | { | ||
2454 | IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; | ||
2455 | } | ||
2456 | return rayCallback.HasHit(); | ||
2457 | } | ||
2458 | } | ||
2459 | } | ||
2460 | return false; | ||
2461 | } | ||
2462 | } | ||
2463 | |||
2464 | |||
2465 | |||
2466 | |||
2467 | public class SimMotionState : DefaultMotionState | ||
2468 | { | ||
2469 | public RigidBody Rigidbody; | ||
2470 | public Vector3 ZeroVect; | ||
2471 | |||
2472 | private IndexedMatrix m_xform; | ||
2473 | |||
2474 | private EntityProperties m_properties; | ||
2475 | private EntityProperties m_lastProperties; | ||
2476 | private BSAPIXNA m_world; | ||
2477 | |||
2478 | const float POSITION_TOLERANCE = 0.05f; | ||
2479 | const float VELOCITY_TOLERANCE = 0.001f; | ||
2480 | const float ROTATION_TOLERANCE = 0.01f; | ||
2481 | const float ANGULARVELOCITY_TOLERANCE = 0.01f; | ||
2482 | |||
2483 | public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates) | ||
2484 | { | ||
2485 | IndexedQuaternion OrientationQuaterion = starTransform.GetRotation(); | ||
2486 | m_properties = new EntityProperties() | ||
2487 | { | ||
2488 | ID = id, | ||
2489 | Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z), | ||
2490 | Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W) | ||
2491 | }; | ||
2492 | m_lastProperties = new EntityProperties() | ||
2493 | { | ||
2494 | ID = id, | ||
2495 | Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z), | ||
2496 | Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W) | ||
2497 | }; | ||
2498 | m_world = pWorld; | ||
2499 | m_xform = starTransform; | ||
2500 | } | ||
2501 | |||
2502 | public override void GetWorldTransform(out IndexedMatrix worldTrans) | ||
2503 | { | ||
2504 | worldTrans = m_xform; | ||
2505 | } | ||
2506 | |||
2507 | public override void SetWorldTransform(IndexedMatrix worldTrans) | ||
2508 | { | ||
2509 | SetWorldTransform(ref worldTrans); | ||
2510 | } | ||
2511 | |||
2512 | public override void SetWorldTransform(ref IndexedMatrix worldTrans) | ||
2513 | { | ||
2514 | SetWorldTransform(ref worldTrans, false); | ||
2515 | } | ||
2516 | public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force) | ||
2517 | { | ||
2518 | m_xform = worldTrans; | ||
2519 | // Put the new transform into m_properties | ||
2520 | IndexedQuaternion OrientationQuaternion = m_xform.GetRotation(); | ||
2521 | IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity(); | ||
2522 | IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity(); | ||
2523 | m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z); | ||
2524 | m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y, | ||
2525 | OrientationQuaternion.Z, OrientationQuaternion.W); | ||
2526 | // A problem with stock Bullet is that we don't get an event when an object is deactivated. | ||
2527 | // This means that the last non-zero values for linear and angular velocity | ||
2528 | // are left in the viewer who does dead reconning and the objects look like | ||
2529 | // they float off. | ||
2530 | // BulletSim ships with a patch to Bullet which creates such an event. | ||
2531 | m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z); | ||
2532 | m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z); | ||
2533 | |||
2534 | if (force | ||
2535 | |||
2536 | || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE) | ||
2537 | || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE) | ||
2538 | // If the Velocity and AngularVelocity are zero, most likely the object has | ||
2539 | // been deactivated. If they both are zero and they have become zero recently, | ||
2540 | // make sure a property update is sent so the zeros make it to the viewer. | ||
2541 | || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect) | ||
2542 | && | ||
2543 | (m_properties.Velocity != m_lastProperties.Velocity || | ||
2544 | m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity)) | ||
2545 | // If Velocity and AngularVelocity are non-zero but have changed, send an update. | ||
2546 | || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE) | ||
2547 | || | ||
2548 | !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity, | ||
2549 | ANGULARVELOCITY_TOLERANCE) | ||
2550 | ) | ||
2551 | |||
2552 | |||
2553 | { | ||
2554 | // Add this update to the list of updates for this frame. | ||
2555 | m_lastProperties = m_properties; | ||
2556 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) | ||
2557 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); | ||
2558 | |||
2559 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; | ||
2560 | } | ||
2561 | |||
2562 | |||
2563 | |||
2564 | |||
2565 | } | ||
2566 | public override void SetRigidBody(RigidBody body) | ||
2567 | { | ||
2568 | Rigidbody = body; | ||
2569 | } | ||
2570 | internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon) | ||
2571 | { | ||
2572 | return | ||
2573 | (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) && | ||
2574 | (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) && | ||
2575 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))); | ||
2576 | } | ||
2577 | |||
2578 | internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon) | ||
2579 | { | ||
2580 | return | ||
2581 | (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) && | ||
2582 | (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) && | ||
2583 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && | ||
2584 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); | ||
2585 | } | ||
2586 | |||
2587 | } | ||
2588 | } | ||
2589 | |||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs new file mode 100755 index 0000000..bde4557 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs | |||
@@ -0,0 +1,457 @@ | |||
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 copyrightD | ||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | using OMV = OpenMetaverse; | ||
37 | |||
38 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
39 | { | ||
40 | public class BSActorAvatarMove : BSActor | ||
41 | { | ||
42 | BSVMotor m_velocityMotor; | ||
43 | |||
44 | // Set to true if we think we're going up stairs. | ||
45 | // This state is remembered because collisions will turn on and off as we go up stairs. | ||
46 | int m_walkingUpStairs; | ||
47 | // The amount the step up is applying. Used to smooth stair walking. | ||
48 | float m_lastStepUp; | ||
49 | |||
50 | // Jumping happens over several frames. If use applies up force while colliding, start the | ||
51 | // jump and allow the jump to continue for this number of frames. | ||
52 | int m_jumpFrames = 0; | ||
53 | float m_jumpVelocity = 0f; | ||
54 | |||
55 | public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
56 | : base(physicsScene, pObj, actorName) | ||
57 | { | ||
58 | m_velocityMotor = null; | ||
59 | m_walkingUpStairs = 0; | ||
60 | m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); | ||
61 | } | ||
62 | |||
63 | // BSActor.isActive | ||
64 | public override bool isActive | ||
65 | { | ||
66 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
67 | } | ||
68 | |||
69 | // Release any connections and resources used by the actor. | ||
70 | // BSActor.Dispose() | ||
71 | public override void Dispose() | ||
72 | { | ||
73 | base.SetEnabled(false); | ||
74 | DeactivateAvatarMove(); | ||
75 | } | ||
76 | |||
77 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
78 | // Called at taint-time. | ||
79 | // BSActor.Refresh() | ||
80 | public override void Refresh() | ||
81 | { | ||
82 | m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); | ||
83 | |||
84 | // If the object is physically active, add the hoverer prestep action | ||
85 | if (isActive) | ||
86 | { | ||
87 | ActivateAvatarMove(); | ||
88 | } | ||
89 | else | ||
90 | { | ||
91 | DeactivateAvatarMove(); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
96 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
97 | // Called at taint-time. | ||
98 | // BSActor.RemoveDependencies() | ||
99 | public override void RemoveDependencies() | ||
100 | { | ||
101 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
102 | } | ||
103 | |||
104 | // Usually called when target velocity changes to set the current velocity and the target | ||
105 | // into the movement motor. | ||
106 | public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) | ||
107 | { | ||
108 | m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate() | ||
109 | { | ||
110 | if (m_velocityMotor != null) | ||
111 | { | ||
112 | // if (targ == OMV.Vector3.Zero) | ||
113 | // Util.PrintCallStack(); | ||
114 | // | ||
115 | // Console.WriteLine("SetVelocityAndTarget, {0} {1}", vel, targ); | ||
116 | m_velocityMotor.Reset(); | ||
117 | m_velocityMotor.SetTarget(targ); | ||
118 | m_velocityMotor.SetCurrent(vel); | ||
119 | m_velocityMotor.Enabled = true; | ||
120 | } | ||
121 | }); | ||
122 | } | ||
123 | |||
124 | // If a hover motor has not been created, create one and start the hovering. | ||
125 | private void ActivateAvatarMove() | ||
126 | { | ||
127 | if (m_velocityMotor == null) | ||
128 | { | ||
129 | // Infinite decay and timescale values so motor only changes current to target values. | ||
130 | m_velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
131 | 0.2f, // time scale | ||
132 | BSMotor.Infinite, // decay time scale | ||
133 | 1f // efficiency | ||
134 | ); | ||
135 | m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold; | ||
136 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
137 | SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); | ||
138 | |||
139 | m_physicsScene.BeforeStep += Mover; | ||
140 | m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty; | ||
141 | |||
142 | m_walkingUpStairs = 0; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | private void DeactivateAvatarMove() | ||
147 | { | ||
148 | if (m_velocityMotor != null) | ||
149 | { | ||
150 | m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty; | ||
151 | m_physicsScene.BeforeStep -= Mover; | ||
152 | m_velocityMotor = null; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
157 | private void Mover(float timeStep) | ||
158 | { | ||
159 | // Don't do movement while the object is selected. | ||
160 | if (!isActive) | ||
161 | return; | ||
162 | |||
163 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
164 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
165 | |||
166 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
167 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
168 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
169 | // component is not fooled with (thus allowing gravity to do its thing). | ||
170 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
171 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
172 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
173 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
174 | // errors can creap in and the avatar will slowly float off in some direction. | ||
175 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
176 | // from real pushing. | ||
177 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
178 | |||
179 | m_velocityMotor.Step(timeStep); | ||
180 | m_controllingPrim.IsStationary = false; | ||
181 | |||
182 | // If we're not supposed to be moving, make sure things are zero. | ||
183 | if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
184 | { | ||
185 | // The avatar shouldn't be moving | ||
186 | m_velocityMotor.Zero(); | ||
187 | |||
188 | if (m_controllingPrim.IsColliding) | ||
189 | { | ||
190 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
191 | if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect) | ||
192 | { | ||
193 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); | ||
194 | m_controllingPrim.IsStationary = true; | ||
195 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
196 | } | ||
197 | |||
198 | // Standing has more friction on the ground | ||
199 | if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) | ||
200 | { | ||
201 | m_controllingPrim.Friction = BSParam.AvatarStandingFriction; | ||
202 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
203 | } | ||
204 | } | ||
205 | else | ||
206 | { | ||
207 | if (m_controllingPrim.Flying) | ||
208 | { | ||
209 | // Flying and not colliding and velocity nearly zero. | ||
210 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | //We are falling but are not touching any keys make sure not falling too fast | ||
215 | if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity) | ||
216 | { | ||
217 | |||
218 | OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass; | ||
219 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce); | ||
220 | } | ||
221 | |||
222 | } | ||
223 | } | ||
224 | |||
225 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", | ||
226 | m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding); | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | // Supposed to be moving. | ||
231 | OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; | ||
232 | |||
233 | if (m_controllingPrim.Friction != BSParam.AvatarFriction) | ||
234 | { | ||
235 | // Probably starting to walk. Set friction to moving friction. | ||
236 | m_controllingPrim.Friction = BSParam.AvatarFriction; | ||
237 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
238 | } | ||
239 | |||
240 | if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) | ||
241 | { | ||
242 | stepVelocity.Z = m_controllingPrim.RawVelocity.Z; | ||
243 | } | ||
244 | |||
245 | // Colliding and not flying with an upward force. The avatar must be trying to jump. | ||
246 | if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0) | ||
247 | { | ||
248 | // We allow the upward force to happen for this many frames. | ||
249 | m_jumpFrames = BSParam.AvatarJumpFrames; | ||
250 | m_jumpVelocity = stepVelocity.Z; | ||
251 | } | ||
252 | |||
253 | // The case where the avatar is not colliding and is not flying is special. | ||
254 | // The avatar is either falling or jumping and the user can be applying force to the avatar | ||
255 | // (force in some direction or force up or down). | ||
256 | // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity. | ||
257 | // If the user is trying to apply upward force but we're not colliding, assume the avatar | ||
258 | // is trying to jump and don't apply the upward force if not touching the ground any more. | ||
259 | if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) | ||
260 | { | ||
261 | // If upward velocity is being applied, this must be a jump and only allow that to go on so long | ||
262 | if (m_jumpFrames > 0) | ||
263 | { | ||
264 | // Since not touching the ground, only apply upward force for so long. | ||
265 | m_jumpFrames--; | ||
266 | stepVelocity.Z = m_jumpVelocity; | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | |||
271 | // Since we're not affected by anything, the avatar must be falling and we do not want that to be too fast. | ||
272 | if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity) | ||
273 | { | ||
274 | |||
275 | stepVelocity.Z = BSParam.AvatarTerminalVelocity; | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | stepVelocity.Z = m_controllingPrim.RawVelocity.Z; | ||
280 | } | ||
281 | } | ||
282 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
283 | } | ||
284 | |||
285 | //Alicia: Maintain minimum height when flying. | ||
286 | // SL has a flying effect that keeps the avatar flying above the ground by some margin | ||
287 | if (m_controllingPrim.Flying) | ||
288 | { | ||
289 | float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition) | ||
290 | + BSParam.AvatarFlyingGroundMargin; | ||
291 | |||
292 | if( m_controllingPrim.Position.Z < hover_height) | ||
293 | { | ||
294 | stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
299 | OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; | ||
300 | |||
301 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
302 | moveForce += WalkUpStairs(); | ||
303 | |||
304 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", | ||
305 | m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); | ||
306 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | // Called just as the property update is received from the physics engine. | ||
311 | // Do any mode necessary for avatar movement. | ||
312 | private void Process_OnPreUpdateProperty(ref EntityProperties entprop) | ||
313 | { | ||
314 | // Don't change position if standing on a stationary object. | ||
315 | if (m_controllingPrim.IsStationary) | ||
316 | { | ||
317 | entprop.Position = m_controllingPrim.RawPosition; | ||
318 | entprop.Velocity = OMV.Vector3.Zero; | ||
319 | m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); | ||
320 | } | ||
321 | |||
322 | } | ||
323 | |||
324 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
325 | // avatar up so it can walk up and over the low objects. | ||
326 | private OMV.Vector3 WalkUpStairs() | ||
327 | { | ||
328 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
329 | |||
330 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", | ||
331 | m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, | ||
332 | m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); | ||
333 | |||
334 | // Check for stairs climbing if colliding, not flying and moving forward | ||
335 | if ( m_controllingPrim.IsColliding | ||
336 | && !m_controllingPrim.Flying | ||
337 | && m_controllingPrim.TargetVelocitySpeed > 0.1f ) | ||
338 | { | ||
339 | // The range near the character's feet where we will consider stairs | ||
340 | // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; | ||
341 | // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off | ||
342 | // from the height. Revisit size and this computation when height is scaled properly. | ||
343 | float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge; | ||
344 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
345 | |||
346 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is. | ||
347 | // Find the highest 'good' collision. | ||
348 | OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero; | ||
349 | foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) | ||
350 | { | ||
351 | // Don't care about collisions with the terrain | ||
352 | if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) | ||
353 | { | ||
354 | BSPhysObject collisionObject; | ||
355 | if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject)) | ||
356 | { | ||
357 | if (!collisionObject.IsVolumeDetect) | ||
358 | { | ||
359 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
360 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
361 | m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
362 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
363 | { | ||
364 | // This contact is within the 'near the feet' range. | ||
365 | // The step is presumed to be more or less vertical. Thus the Z component should | ||
366 | // be nearly horizontal. | ||
367 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; | ||
368 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
369 | const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles | ||
370 | // m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}", | ||
371 | // m_controllingPrim.LocalID, directionFacing, touchNormal, | ||
372 | // Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) ); | ||
373 | if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle | ||
374 | && (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle) | ||
375 | { | ||
376 | // The normal should be our contact point to the object so it is pointing away | ||
377 | // thus the difference between our facing orientation and the normal should be small. | ||
378 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
379 | if (diff < BSParam.AvatarStepApproachFactor) | ||
380 | { | ||
381 | if (highestTouchPosition.Z < touchPosition.Z) | ||
382 | highestTouchPosition = touchPosition; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | } | ||
390 | m_walkingUpStairs = 0; | ||
391 | // If there is a good step sensing, move the avatar over the step. | ||
392 | if (highestTouchPosition != OMV.Vector3.Zero) | ||
393 | { | ||
394 | // Remember that we are going up stairs. This is needed because collisions | ||
395 | // will stop when we move up so this smoothes out that effect. | ||
396 | m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps; | ||
397 | |||
398 | m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin; | ||
399 | ret = ComputeStairCorrection(m_lastStepUp); | ||
400 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}", | ||
401 | m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret); | ||
402 | } | ||
403 | } | ||
404 | else | ||
405 | { | ||
406 | // If we used to be going up stairs but are not now, smooth the case where collision goes away while | ||
407 | // we are bouncing up the stairs. | ||
408 | if (m_walkingUpStairs > 0) | ||
409 | { | ||
410 | m_walkingUpStairs--; | ||
411 | ret = ComputeStairCorrection(m_lastStepUp); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | private OMV.Vector3 ComputeStairCorrection(float stepUp) | ||
419 | { | ||
420 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
421 | OMV.Vector3 displacement = OMV.Vector3.Zero; | ||
422 | |||
423 | if (stepUp > 0f) | ||
424 | { | ||
425 | // Found the stairs contact point. Push up a little to raise the character. | ||
426 | if (BSParam.AvatarStepForceFactor > 0f) | ||
427 | { | ||
428 | float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; | ||
429 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
430 | } | ||
431 | |||
432 | // Also move the avatar up for the new height | ||
433 | if (BSParam.AvatarStepUpCorrectionFactor > 0f) | ||
434 | { | ||
435 | // Move the avatar up related to the height of the collision | ||
436 | displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); | ||
437 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
438 | } | ||
439 | else | ||
440 | { | ||
441 | if (BSParam.AvatarStepUpCorrectionFactor < 0f) | ||
442 | { | ||
443 | // Move the avatar up about the specified step height | ||
444 | displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); | ||
445 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
446 | } | ||
447 | } | ||
448 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,stepUp={1},isp={2},force={3}", | ||
449 | m_controllingPrim.LocalID, stepUp, displacement, ret); | ||
450 | |||
451 | } | ||
452 | return ret; | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | |||
457 | |||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs new file mode 100755 index 0000000..e54c27b --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs | |||
@@ -0,0 +1,174 @@ | |||
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 copyrightD | ||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorHover : BSActor | ||
40 | { | ||
41 | private BSFMotor m_hoverMotor; | ||
42 | |||
43 | public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_hoverMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | DeactivateHover(); | ||
62 | } | ||
63 | |||
64 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
65 | // Called at taint-time. | ||
66 | // BSActor.Refresh() | ||
67 | public override void Refresh() | ||
68 | { | ||
69 | m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID); | ||
70 | |||
71 | // If not active any more, turn me off | ||
72 | if (!m_controllingPrim.HoverActive) | ||
73 | { | ||
74 | SetEnabled(false); | ||
75 | } | ||
76 | |||
77 | // If the object is physically active, add the hoverer prestep action | ||
78 | if (isActive) | ||
79 | { | ||
80 | ActivateHover(); | ||
81 | } | ||
82 | else | ||
83 | { | ||
84 | DeactivateHover(); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
89 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
90 | // Called at taint-time. | ||
91 | // BSActor.RemoveDependencies() | ||
92 | public override void RemoveDependencies() | ||
93 | { | ||
94 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
95 | } | ||
96 | |||
97 | // If a hover motor has not been created, create one and start the hovering. | ||
98 | private void ActivateHover() | ||
99 | { | ||
100 | if (m_hoverMotor == null) | ||
101 | { | ||
102 | // Turning the target on | ||
103 | m_hoverMotor = new BSFMotor("BSActorHover", | ||
104 | m_controllingPrim.HoverTau, // timeScale | ||
105 | BSMotor.Infinite, // decay time scale | ||
106 | 1f // efficiency | ||
107 | ); | ||
108 | m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); | ||
109 | m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); | ||
110 | m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
111 | |||
112 | m_physicsScene.BeforeStep += Hoverer; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | private void DeactivateHover() | ||
117 | { | ||
118 | if (m_hoverMotor != null) | ||
119 | { | ||
120 | m_physicsScene.BeforeStep -= Hoverer; | ||
121 | m_hoverMotor = null; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
126 | private void Hoverer(float timeStep) | ||
127 | { | ||
128 | // Don't do hovering while the object is selected. | ||
129 | if (!isActive) | ||
130 | return; | ||
131 | |||
132 | m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); | ||
133 | m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); | ||
134 | float targetHeight = m_hoverMotor.Step(timeStep); | ||
135 | |||
136 | // 'targetHeight' is where we'd like the Z of the prim to be at this moment. | ||
137 | // Compute the amount of force to push us there. | ||
138 | float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass; | ||
139 | // Undo anything the object thinks it's doing at the moment | ||
140 | moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass; | ||
141 | |||
142 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce)); | ||
143 | m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", | ||
144 | m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass); | ||
145 | } | ||
146 | |||
147 | // Based on current position, determine what we should be hovering at now. | ||
148 | // Must recompute often. What if we walked offa cliff> | ||
149 | private float ComputeCurrentHoverHeight() | ||
150 | { | ||
151 | float ret = m_controllingPrim.HoverHeight; | ||
152 | float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition); | ||
153 | |||
154 | switch (m_controllingPrim.HoverType) | ||
155 | { | ||
156 | case PIDHoverType.Ground: | ||
157 | ret = groundHeight + m_controllingPrim.HoverHeight; | ||
158 | break; | ||
159 | case PIDHoverType.GroundAndWater: | ||
160 | float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition); | ||
161 | if (groundHeight > waterHeight) | ||
162 | { | ||
163 | ret = groundHeight + m_controllingPrim.HoverHeight; | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | ret = waterHeight + m_controllingPrim.HoverHeight; | ||
168 | } | ||
169 | break; | ||
170 | } | ||
171 | return ret; | ||
172 | } | ||
173 | } | ||
174 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs new file mode 100755 index 0000000..3b3c161 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs | |||
@@ -0,0 +1,219 @@ | |||
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 copyrightD | ||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OMV = OpenMetaverse; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public class BSActorLockAxis : BSActor | ||
38 | { | ||
39 | private BSConstraint LockAxisConstraint = null; | ||
40 | private bool HaveRegisteredForBeforeStepCallback = false; | ||
41 | |||
42 | // The lock access flags (which axises were locked) when the contraint was built. | ||
43 | // Used to see if locking has changed since when the constraint was built. | ||
44 | OMV.Vector3 LockAxisLinearFlags; | ||
45 | OMV.Vector3 LockAxisAngularFlags; | ||
46 | |||
47 | public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
48 | : base(physicsScene, pObj, actorName) | ||
49 | { | ||
50 | m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); | ||
51 | LockAxisConstraint = null; | ||
52 | HaveRegisteredForBeforeStepCallback = false; | ||
53 | } | ||
54 | |||
55 | // BSActor.isActive | ||
56 | public override bool isActive | ||
57 | { | ||
58 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
59 | } | ||
60 | |||
61 | // Release any connections and resources used by the actor. | ||
62 | // BSActor.Dispose() | ||
63 | public override void Dispose() | ||
64 | { | ||
65 | Enabled = false; | ||
66 | UnRegisterForBeforeStepCallback(); | ||
67 | RemoveAxisLockConstraint(); | ||
68 | } | ||
69 | |||
70 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
71 | // Called at taint-time. | ||
72 | // BSActor.Refresh() | ||
73 | public override void Refresh() | ||
74 | { | ||
75 | // Since the axis logging is done with a constraint, Refresh() time is good for | ||
76 | // changing parameters but this needs to wait until the prim/linkset is physically | ||
77 | // constructed. Therefore, the constraint itself is placed at pre-step time. | ||
78 | |||
79 | // If all the axis are free, we don't need to exist | ||
80 | // Refresh() only turns off. Enabling is done by InitializeAxisActor() | ||
81 | // whenever parameters are changed. | ||
82 | // This leaves 'enable' free to turn off an actor when it is not wanted to run. | ||
83 | if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree | ||
84 | && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) | ||
85 | { | ||
86 | Enabled = false; | ||
87 | } | ||
88 | |||
89 | if (isActive) | ||
90 | { | ||
91 | RegisterForBeforeStepCallback(); | ||
92 | } | ||
93 | else | ||
94 | { | ||
95 | RemoveDependencies(); | ||
96 | UnRegisterForBeforeStepCallback(); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
101 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
102 | // Called at taint-time. | ||
103 | // BSActor.RemoveDependencies() | ||
104 | public override void RemoveDependencies() | ||
105 | { | ||
106 | RemoveAxisLockConstraint(); | ||
107 | } | ||
108 | |||
109 | private void RegisterForBeforeStepCallback() | ||
110 | { | ||
111 | if (!HaveRegisteredForBeforeStepCallback) | ||
112 | { | ||
113 | m_physicsScene.BeforeStep += PhysicsScene_BeforeStep; | ||
114 | HaveRegisteredForBeforeStepCallback = true; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | private void UnRegisterForBeforeStepCallback() | ||
119 | { | ||
120 | if (HaveRegisteredForBeforeStepCallback) | ||
121 | { | ||
122 | m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep; | ||
123 | HaveRegisteredForBeforeStepCallback = false; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | private void PhysicsScene_BeforeStep(float timestep) | ||
128 | { | ||
129 | // If all the axis are free, we don't need to exist | ||
130 | if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree | ||
131 | && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) | ||
132 | { | ||
133 | Enabled = false; | ||
134 | } | ||
135 | |||
136 | // If the object is physically active, add the axis locking constraint | ||
137 | if (isActive) | ||
138 | { | ||
139 | // Check to see if the locking parameters have changed | ||
140 | if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags | ||
141 | || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags) | ||
142 | { | ||
143 | // The locking has changed. Remove the old constraint and build a new one | ||
144 | RemoveAxisLockConstraint(); | ||
145 | } | ||
146 | |||
147 | AddAxisLockConstraint(); | ||
148 | } | ||
149 | else | ||
150 | { | ||
151 | RemoveAxisLockConstraint(); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | // Note that this relies on being called at TaintTime | ||
156 | private void AddAxisLockConstraint() | ||
157 | { | ||
158 | if (LockAxisConstraint == null) | ||
159 | { | ||
160 | // Lock that axis by creating a 6DOF constraint that has one end in the world and | ||
161 | // the other in the object. | ||
162 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 | ||
163 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 | ||
164 | |||
165 | // Remove any existing axis constraint (just to be sure) | ||
166 | RemoveAxisLockConstraint(); | ||
167 | |||
168 | BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, | ||
169 | OMV.Vector3.Zero, OMV.Quaternion.Identity, | ||
170 | false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); | ||
171 | LockAxisConstraint = axisConstrainer; | ||
172 | m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); | ||
173 | |||
174 | // Remember the clocking being inforced so we can notice if they have changed | ||
175 | LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis; | ||
176 | LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis; | ||
177 | |||
178 | // The constraint is tied to the world and oriented to the prim. | ||
179 | |||
180 | if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh)) | ||
181 | { | ||
182 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits", | ||
183 | m_controllingPrim.LocalID); | ||
184 | } | ||
185 | |||
186 | if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh)) | ||
187 | { | ||
188 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", | ||
189 | m_controllingPrim.LocalID); | ||
190 | } | ||
191 | |||
192 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", | ||
193 | m_controllingPrim.LocalID, | ||
194 | m_controllingPrim.LockedLinearAxisLow, | ||
195 | m_controllingPrim.LockedLinearAxisHigh, | ||
196 | m_controllingPrim.LockedAngularAxisLow, | ||
197 | m_controllingPrim.LockedAngularAxisHigh); | ||
198 | |||
199 | // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. | ||
200 | axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); | ||
201 | |||
202 | axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); | ||
203 | |||
204 | RegisterForBeforeStepCallback(); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | private void RemoveAxisLockConstraint() | ||
209 | { | ||
210 | UnRegisterForBeforeStepCallback(); | ||
211 | if (LockAxisConstraint != null) | ||
212 | { | ||
213 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); | ||
214 | LockAxisConstraint = null; | ||
215 | m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID); | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs new file mode 100755 index 0000000..1145006 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs | |||
@@ -0,0 +1,220 @@ | |||
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 copyrightD | ||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorMoveToTarget : BSActor | ||
40 | { | ||
41 | private BSVMotor m_targetMotor; | ||
42 | |||
43 | public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_targetMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | // MoveToTarget only works on physical prims | ||
54 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
55 | } | ||
56 | |||
57 | // Release any connections and resources used by the actor. | ||
58 | // BSActor.Dispose() | ||
59 | public override void Dispose() | ||
60 | { | ||
61 | Enabled = false; | ||
62 | DeactivateMoveToTarget(); | ||
63 | } | ||
64 | |||
65 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
66 | // Called at taint-time. | ||
67 | // BSActor.Refresh() | ||
68 | public override void Refresh() | ||
69 | { | ||
70 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}", | ||
71 | m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive, | ||
72 | m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau ); | ||
73 | |||
74 | // If not active any more... | ||
75 | if (!m_controllingPrim.MoveToTargetActive) | ||
76 | { | ||
77 | Enabled = false; | ||
78 | } | ||
79 | |||
80 | if (isActive) | ||
81 | { | ||
82 | ActivateMoveToTarget(); | ||
83 | } | ||
84 | else | ||
85 | { | ||
86 | DeactivateMoveToTarget(); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
91 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
92 | // Called at taint-time. | ||
93 | // BSActor.RemoveDependencies() | ||
94 | public override void RemoveDependencies() | ||
95 | { | ||
96 | // Nothing to do for the moveToTarget since it is all software at pre-step action time. | ||
97 | } | ||
98 | |||
99 | // If a hover motor has not been created, create one and start the hovering. | ||
100 | private void ActivateMoveToTarget() | ||
101 | { | ||
102 | if (m_targetMotor == null) | ||
103 | { | ||
104 | // We're taking over after this. | ||
105 | m_controllingPrim.ZeroMotion(true); | ||
106 | |||
107 | /* Someday use the PID controller | ||
108 | m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString()); | ||
109 | m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau; | ||
110 | m_targetMotor.Efficiency = 1f; | ||
111 | */ | ||
112 | m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(), | ||
113 | m_controllingPrim.MoveToTargetTau, // timeScale | ||
114 | BSMotor.Infinite, // decay time scale | ||
115 | 1f // efficiency | ||
116 | ); | ||
117 | m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
118 | m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); | ||
119 | m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); | ||
120 | |||
121 | // m_physicsScene.BeforeStep += Mover; | ||
122 | m_physicsScene.BeforeStep += Mover2; | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | // If already allocated, make sure the target and other paramters are current | ||
127 | m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); | ||
128 | m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | private void DeactivateMoveToTarget() | ||
133 | { | ||
134 | if (m_targetMotor != null) | ||
135 | { | ||
136 | // m_physicsScene.BeforeStep -= Mover; | ||
137 | m_physicsScene.BeforeStep -= Mover2; | ||
138 | m_targetMotor = null; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | // Origional mover that set the objects position to move to the target. | ||
143 | // The problem was that gravity would keep trying to push the object down so | ||
144 | // the overall downward velocity would increase to infinity. | ||
145 | // Called just before the simulation step. | ||
146 | private void Mover(float timeStep) | ||
147 | { | ||
148 | // Don't do hovering while the object is selected. | ||
149 | if (!isActive) | ||
150 | return; | ||
151 | |||
152 | OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) | ||
153 | |||
154 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
155 | OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); | ||
156 | |||
157 | // If we are very close to our target, turn off the movement motor. | ||
158 | if (m_targetMotor.ErrorIsZero()) | ||
159 | { | ||
160 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", | ||
161 | m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); | ||
162 | m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; | ||
163 | m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; | ||
164 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
165 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | m_controllingPrim.ForcePosition = movePosition; | ||
170 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
171 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
172 | } | ||
173 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", | ||
174 | m_controllingPrim.LocalID, origPosition, movePosition); | ||
175 | } | ||
176 | |||
177 | // Version of mover that applies forces to move the physical object to the target. | ||
178 | // Also overcomes gravity so the object doesn't just drop to the ground. | ||
179 | // Called just before the simulation step. | ||
180 | private void Mover2(float timeStep) | ||
181 | { | ||
182 | // Don't do hovering while the object is selected. | ||
183 | if (!isActive) | ||
184 | return; | ||
185 | |||
186 | OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) | ||
187 | OMV.Vector3 addedForce = OMV.Vector3.Zero; | ||
188 | |||
189 | // CorrectionVector is the movement vector required this step | ||
190 | OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition); | ||
191 | |||
192 | // If we are very close to our target, turn off the movement motor. | ||
193 | if (m_targetMotor.ErrorIsZero()) | ||
194 | { | ||
195 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}", | ||
196 | m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass); | ||
197 | m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; | ||
198 | m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; | ||
199 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
200 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // First force to move us there -- the motor return a timestep scaled value. | ||
205 | addedForce = correctionVector / timeStep; | ||
206 | // Remove the existing velocity (only the moveToTarget force counts) | ||
207 | addedForce -= m_controllingPrim.RawVelocity; | ||
208 | // Overcome gravity. | ||
209 | addedForce -= m_controllingPrim.Gravity; | ||
210 | |||
211 | // Add enough force to overcome the mass of the object | ||
212 | addedForce *= m_controllingPrim.Mass; | ||
213 | |||
214 | m_controllingPrim.AddForce(addedForce, false /* pushForce */, true /* inTaintTime */); | ||
215 | } | ||
216 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}", | ||
217 | m_controllingPrim.LocalID, origPosition, addedForce); | ||
218 | } | ||
219 | } | ||
220 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs new file mode 100755 index 0000000..4e81363 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs | |||
@@ -0,0 +1,138 @@ | |||
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 copyrightD | ||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorSetForce : BSActor | ||
40 | { | ||
41 | BSFMotor m_forceMotor; | ||
42 | |||
43 | public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_forceMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | DeactivateSetForce(); | ||
62 | } | ||
63 | |||
64 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
65 | // Called at taint-time. | ||
66 | // BSActor.Refresh() | ||
67 | public override void Refresh() | ||
68 | { | ||
69 | m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID); | ||
70 | |||
71 | // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) | ||
72 | if (m_controllingPrim.RawForce == OMV.Vector3.Zero) | ||
73 | { | ||
74 | m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName); | ||
75 | Enabled = false; | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | // If the object is physically active, add the hoverer prestep action | ||
80 | if (isActive) | ||
81 | { | ||
82 | ActivateSetForce(); | ||
83 | } | ||
84 | else | ||
85 | { | ||
86 | DeactivateSetForce(); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
91 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
92 | // Called at taint-time. | ||
93 | // BSActor.RemoveDependencies() | ||
94 | public override void RemoveDependencies() | ||
95 | { | ||
96 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
97 | } | ||
98 | |||
99 | // If a hover motor has not been created, create one and start the hovering. | ||
100 | private void ActivateSetForce() | ||
101 | { | ||
102 | if (m_forceMotor == null) | ||
103 | { | ||
104 | // A fake motor that might be used someday | ||
105 | m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f); | ||
106 | |||
107 | m_physicsScene.BeforeStep += Mover; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | private void DeactivateSetForce() | ||
112 | { | ||
113 | if (m_forceMotor != null) | ||
114 | { | ||
115 | m_physicsScene.BeforeStep -= Mover; | ||
116 | m_forceMotor = null; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
121 | private void Mover(float timeStep) | ||
122 | { | ||
123 | // Don't do force while the object is selected. | ||
124 | if (!isActive) | ||
125 | return; | ||
126 | |||
127 | m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce); | ||
128 | if (m_controllingPrim.PhysBody.HasPhysicalBody) | ||
129 | { | ||
130 | m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce); | ||
131 | m_controllingPrim.ActivateIfPhysical(false); | ||
132 | } | ||
133 | |||
134 | // TODO: | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs new file mode 100755 index 0000000..79e1d38 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs | |||
@@ -0,0 +1,139 @@ | |||
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 copyrightD | ||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorSetTorque : BSActor | ||
40 | { | ||
41 | BSFMotor m_torqueMotor; | ||
42 | |||
43 | public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_torqueMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | DeactivateSetTorque(); | ||
62 | } | ||
63 | |||
64 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
65 | // Called at taint-time. | ||
66 | // BSActor.Refresh() | ||
67 | public override void Refresh() | ||
68 | { | ||
69 | m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); | ||
70 | |||
71 | // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) | ||
72 | if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) | ||
73 | { | ||
74 | m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName); | ||
75 | Enabled = false; | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | // If the object is physically active, add the hoverer prestep action | ||
80 | if (isActive) | ||
81 | { | ||
82 | ActivateSetTorque(); | ||
83 | } | ||
84 | else | ||
85 | { | ||
86 | DeactivateSetTorque(); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
91 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
92 | // Called at taint-time. | ||
93 | // BSActor.RemoveDependencies() | ||
94 | public override void RemoveDependencies() | ||
95 | { | ||
96 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
97 | } | ||
98 | |||
99 | // If a hover motor has not been created, create one and start the hovering. | ||
100 | private void ActivateSetTorque() | ||
101 | { | ||
102 | if (m_torqueMotor == null) | ||
103 | { | ||
104 | // A fake motor that might be used someday | ||
105 | m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f); | ||
106 | |||
107 | m_physicsScene.BeforeStep += Mover; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | private void DeactivateSetTorque() | ||
112 | { | ||
113 | if (m_torqueMotor != null) | ||
114 | { | ||
115 | m_physicsScene.BeforeStep -= Mover; | ||
116 | m_torqueMotor = null; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
121 | private void Mover(float timeStep) | ||
122 | { | ||
123 | // Don't do force while the object is selected. | ||
124 | if (!isActive) | ||
125 | return; | ||
126 | |||
127 | m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); | ||
128 | if (m_controllingPrim.PhysBody.HasPhysicalBody) | ||
129 | { | ||
130 | m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true); | ||
131 | m_controllingPrim.ActivateIfPhysical(false); | ||
132 | } | ||
133 | |||
134 | // TODO: | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | |||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs new file mode 100755 index 0000000..7f45e2c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs | |||
@@ -0,0 +1,154 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
32 | { | ||
33 | public class BSActorCollection | ||
34 | { | ||
35 | private Dictionary<string, BSActor> m_actors; | ||
36 | |||
37 | public BSActorCollection() | ||
38 | { | ||
39 | m_actors = new Dictionary<string, BSActor>(); | ||
40 | } | ||
41 | public void Add(string name, BSActor actor) | ||
42 | { | ||
43 | lock (m_actors) | ||
44 | { | ||
45 | if (!m_actors.ContainsKey(name)) | ||
46 | { | ||
47 | m_actors[name] = actor; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | public bool RemoveAndRelease(string name) | ||
52 | { | ||
53 | bool ret = false; | ||
54 | lock (m_actors) | ||
55 | { | ||
56 | if (m_actors.ContainsKey(name)) | ||
57 | { | ||
58 | BSActor beingRemoved = m_actors[name]; | ||
59 | m_actors.Remove(name); | ||
60 | beingRemoved.Dispose(); | ||
61 | ret = true; | ||
62 | } | ||
63 | } | ||
64 | return ret; | ||
65 | } | ||
66 | public void Clear() | ||
67 | { | ||
68 | lock (m_actors) | ||
69 | { | ||
70 | ForEachActor(a => a.Dispose()); | ||
71 | m_actors.Clear(); | ||
72 | } | ||
73 | } | ||
74 | public void Dispose() | ||
75 | { | ||
76 | Clear(); | ||
77 | } | ||
78 | public bool HasActor(string name) | ||
79 | { | ||
80 | return m_actors.ContainsKey(name); | ||
81 | } | ||
82 | public bool TryGetActor(string actorName, out BSActor theActor) | ||
83 | { | ||
84 | return m_actors.TryGetValue(actorName, out theActor); | ||
85 | } | ||
86 | public void ForEachActor(Action<BSActor> act) | ||
87 | { | ||
88 | lock (m_actors) | ||
89 | { | ||
90 | foreach (KeyValuePair<string, BSActor> kvp in m_actors) | ||
91 | act(kvp.Value); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | public void Enable(bool enabl) | ||
96 | { | ||
97 | ForEachActor(a => a.SetEnabled(enabl)); | ||
98 | } | ||
99 | public void Refresh() | ||
100 | { | ||
101 | ForEachActor(a => a.Refresh()); | ||
102 | } | ||
103 | public void RemoveDependencies() | ||
104 | { | ||
105 | ForEachActor(a => a.RemoveDependencies()); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // ============================================================================= | ||
110 | /// <summary> | ||
111 | /// Each physical object can have 'actors' who are pushing the object around. | ||
112 | /// This can be used for hover, locking axis, making vehicles, etc. | ||
113 | /// Each physical object can have multiple actors acting on it. | ||
114 | /// | ||
115 | /// An actor usually registers itself with physics scene events (pre-step action) | ||
116 | /// and modifies the parameters on the host physical object. | ||
117 | /// </summary> | ||
118 | public abstract class BSActor | ||
119 | { | ||
120 | protected BSScene m_physicsScene { get; private set; } | ||
121 | protected BSPhysObject m_controllingPrim { get; private set; } | ||
122 | public virtual bool Enabled { get; set; } | ||
123 | public string ActorName { get; private set; } | ||
124 | |||
125 | public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
126 | { | ||
127 | m_physicsScene = physicsScene; | ||
128 | m_controllingPrim = pObj; | ||
129 | ActorName = actorName; | ||
130 | Enabled = true; | ||
131 | } | ||
132 | |||
133 | // Return 'true' if activily updating the prim | ||
134 | public virtual bool isActive | ||
135 | { | ||
136 | get { return Enabled; } | ||
137 | } | ||
138 | |||
139 | // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled. | ||
140 | // Anyone else should assign true/false to 'Enabled'. | ||
141 | public void SetEnabled(bool setEnabled) | ||
142 | { | ||
143 | Enabled = setEnabled; | ||
144 | } | ||
145 | // Release any connections and resources used by the actor. | ||
146 | public abstract void Dispose(); | ||
147 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
148 | public abstract void Refresh(); | ||
149 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
150 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
151 | public abstract void RemoveDependencies(); | ||
152 | |||
153 | } | ||
154 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs new file mode 100644 index 0000000..8491c0f --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs | |||
@@ -0,0 +1,763 @@ | |||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Runtime.InteropServices; | ||
30 | using System.Security; | ||
31 | using System.Text; | ||
32 | using OpenMetaverse; | ||
33 | |||
34 | namespace OpenSim.Region.Physics.BulletSPlugin { | ||
35 | |||
36 | // Constraint type values as defined by Bullet | ||
37 | public enum ConstraintType : int | ||
38 | { | ||
39 | POINT2POINT_CONSTRAINT_TYPE = 3, | ||
40 | HINGE_CONSTRAINT_TYPE, | ||
41 | CONETWIST_CONSTRAINT_TYPE, | ||
42 | D6_CONSTRAINT_TYPE, | ||
43 | SLIDER_CONSTRAINT_TYPE, | ||
44 | CONTACT_CONSTRAINT_TYPE, | ||
45 | D6_SPRING_CONSTRAINT_TYPE, | ||
46 | GEAR_CONSTRAINT_TYPE, // added in Bullet 2.82 | ||
47 | FIXED_CONSTRAINT_TYPE, // added in Bullet 2.82 | ||
48 | MAX_CONSTRAINT_TYPE, // last type defined by Bullet | ||
49 | // | ||
50 | BS_FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving | ||
51 | } | ||
52 | |||
53 | // =============================================================================== | ||
54 | [StructLayout(LayoutKind.Sequential)] | ||
55 | public struct ConvexHull | ||
56 | { | ||
57 | Vector3 Offset; | ||
58 | int VertexCount; | ||
59 | Vector3[] Vertices; | ||
60 | } | ||
61 | public enum BSPhysicsShapeType | ||
62 | { | ||
63 | SHAPE_UNKNOWN = 0, | ||
64 | SHAPE_CAPSULE = 1, | ||
65 | SHAPE_BOX = 2, | ||
66 | SHAPE_CONE = 3, | ||
67 | SHAPE_CYLINDER = 4, | ||
68 | SHAPE_SPHERE = 5, | ||
69 | SHAPE_MESH = 6, | ||
70 | SHAPE_HULL = 7, | ||
71 | // following defined by BulletSim | ||
72 | SHAPE_GROUNDPLANE = 20, | ||
73 | SHAPE_TERRAIN = 21, | ||
74 | SHAPE_COMPOUND = 22, | ||
75 | SHAPE_HEIGHTMAP = 23, | ||
76 | SHAPE_AVATAR = 24, | ||
77 | SHAPE_CONVEXHULL= 25, | ||
78 | SHAPE_GIMPACT = 26, | ||
79 | }; | ||
80 | |||
81 | // The native shapes have predefined shape hash keys | ||
82 | public enum FixedShapeKey : ulong | ||
83 | { | ||
84 | KEY_NONE = 0, | ||
85 | KEY_BOX = 1, | ||
86 | KEY_SPHERE = 2, | ||
87 | KEY_CONE = 3, | ||
88 | KEY_CYLINDER = 4, | ||
89 | KEY_CAPSULE = 5, | ||
90 | KEY_AVATAR = 6, | ||
91 | } | ||
92 | |||
93 | [StructLayout(LayoutKind.Sequential)] | ||
94 | public struct ShapeData | ||
95 | { | ||
96 | public UInt32 ID; | ||
97 | public BSPhysicsShapeType Type; | ||
98 | public Vector3 Position; | ||
99 | public Quaternion Rotation; | ||
100 | public Vector3 Velocity; | ||
101 | public Vector3 Scale; | ||
102 | public float Mass; | ||
103 | public float Buoyancy; | ||
104 | public System.UInt64 HullKey; | ||
105 | public System.UInt64 MeshKey; | ||
106 | public float Friction; | ||
107 | public float Restitution; | ||
108 | public float Collidable; // true of things bump into this | ||
109 | public float Static; // true if a static object. Otherwise gravity, etc. | ||
110 | public float Solid; // true if object cannot be passed through | ||
111 | public Vector3 Size; | ||
112 | |||
113 | // note that bools are passed as floats since bool size changes by language and architecture | ||
114 | public const float numericTrue = 1f; | ||
115 | public const float numericFalse = 0f; | ||
116 | } | ||
117 | [StructLayout(LayoutKind.Sequential)] | ||
118 | public struct SweepHit | ||
119 | { | ||
120 | public UInt32 ID; | ||
121 | public float Fraction; | ||
122 | public Vector3 Normal; | ||
123 | public Vector3 Point; | ||
124 | } | ||
125 | [StructLayout(LayoutKind.Sequential)] | ||
126 | public struct RaycastHit | ||
127 | { | ||
128 | public UInt32 ID; | ||
129 | public float Fraction; | ||
130 | public Vector3 Normal; | ||
131 | } | ||
132 | [StructLayout(LayoutKind.Sequential)] | ||
133 | public struct CollisionDesc | ||
134 | { | ||
135 | public UInt32 aID; | ||
136 | public UInt32 bID; | ||
137 | public Vector3 point; | ||
138 | public Vector3 normal; | ||
139 | public float penetration; | ||
140 | } | ||
141 | [StructLayout(LayoutKind.Sequential)] | ||
142 | public struct EntityProperties | ||
143 | { | ||
144 | public UInt32 ID; | ||
145 | public Vector3 Position; | ||
146 | public Quaternion Rotation; | ||
147 | public Vector3 Velocity; | ||
148 | public Vector3 Acceleration; | ||
149 | public Vector3 RotationalVelocity; | ||
150 | |||
151 | public override string ToString() | ||
152 | { | ||
153 | StringBuilder buff = new StringBuilder(); | ||
154 | buff.Append("<i="); | ||
155 | buff.Append(ID.ToString()); | ||
156 | buff.Append(",p="); | ||
157 | buff.Append(Position.ToString()); | ||
158 | buff.Append(",r="); | ||
159 | buff.Append(Rotation.ToString()); | ||
160 | buff.Append(",v="); | ||
161 | buff.Append(Velocity.ToString()); | ||
162 | buff.Append(",a="); | ||
163 | buff.Append(Acceleration.ToString()); | ||
164 | buff.Append(",rv="); | ||
165 | buff.Append(RotationalVelocity.ToString()); | ||
166 | buff.Append(">"); | ||
167 | return buff.ToString(); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | // Format of this structure must match the definition in the C++ code | ||
172 | // NOTE: adding the X causes compile breaks if used. These are unused symbols | ||
173 | // that can be removed from both here and the unmanaged definition of this structure. | ||
174 | [StructLayout(LayoutKind.Sequential)] | ||
175 | public struct ConfigurationParameters | ||
176 | { | ||
177 | public float defaultFriction; | ||
178 | public float defaultDensity; | ||
179 | public float defaultRestitution; | ||
180 | public float collisionMargin; | ||
181 | public float gravity; | ||
182 | |||
183 | public float maxPersistantManifoldPoolSize; | ||
184 | public float maxCollisionAlgorithmPoolSize; | ||
185 | public float shouldDisableContactPoolDynamicAllocation; | ||
186 | public float shouldForceUpdateAllAabbs; | ||
187 | public float shouldRandomizeSolverOrder; | ||
188 | public float shouldSplitSimulationIslands; | ||
189 | public float shouldEnableFrictionCaching; | ||
190 | public float numberOfSolverIterations; | ||
191 | public float useSingleSidedMeshes; | ||
192 | public float globalContactBreakingThreshold; | ||
193 | |||
194 | public float physicsLoggingFrames; | ||
195 | |||
196 | public const float numericTrue = 1f; | ||
197 | public const float numericFalse = 0f; | ||
198 | } | ||
199 | |||
200 | // Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library. | ||
201 | [StructLayout(LayoutKind.Sequential)] | ||
202 | public struct HACDParams | ||
203 | { | ||
204 | // usual default values | ||
205 | public float maxVerticesPerHull; // 100 | ||
206 | public float minClusters; // 2 | ||
207 | public float compacityWeight; // 0.1 | ||
208 | public float volumeWeight; // 0.0 | ||
209 | public float concavity; // 100 | ||
210 | public float addExtraDistPoints; // false | ||
211 | public float addNeighboursDistPoints; // false | ||
212 | public float addFacesPoints; // false | ||
213 | public float shouldAdjustCollisionMargin; // false | ||
214 | // VHACD | ||
215 | public float whichHACD; // zero if Bullet HACD, non-zero says VHACD | ||
216 | // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html | ||
217 | public float vHACDresolution; // 100,000 max number of voxels generated during voxelization stage | ||
218 | public float vHACDdepth; // 20 max number of clipping stages | ||
219 | public float vHACDconcavity; // 0.0025 maximum concavity | ||
220 | public float vHACDplaneDownsampling; // 4 granularity of search for best clipping plane | ||
221 | public float vHACDconvexHullDownsampling; // 4 precision of hull gen process | ||
222 | public float vHACDalpha; // 0.05 bias toward clipping along symmetry planes | ||
223 | public float vHACDbeta; // 0.05 bias toward clipping along revolution axis | ||
224 | public float vHACDgamma; // 0.00125 max concavity when merging | ||
225 | public float vHACDpca; // 0 on/off normalizing mesh before decomp | ||
226 | public float vHACDmode; // 0 0:voxel based, 1: tetrahedron based | ||
227 | public float vHACDmaxNumVerticesPerCH; // 64 max triangles per convex hull | ||
228 | public float vHACDminVolumePerCH; // 0.0001 sampling of generated convex hulls | ||
229 | } | ||
230 | |||
231 | // The states a bullet collision object can have | ||
232 | public enum ActivationState : uint | ||
233 | { | ||
234 | ACTIVE_TAG = 1, | ||
235 | ISLAND_SLEEPING, | ||
236 | WANTS_DEACTIVATION, | ||
237 | DISABLE_DEACTIVATION, | ||
238 | DISABLE_SIMULATION, | ||
239 | } | ||
240 | |||
241 | public enum CollisionObjectTypes : int | ||
242 | { | ||
243 | CO_COLLISION_OBJECT = 1 << 0, | ||
244 | CO_RIGID_BODY = 1 << 1, | ||
245 | CO_GHOST_OBJECT = 1 << 2, | ||
246 | CO_SOFT_BODY = 1 << 3, | ||
247 | CO_HF_FLUID = 1 << 4, | ||
248 | CO_USER_TYPE = 1 << 5, | ||
249 | } | ||
250 | |||
251 | // Values used by Bullet and BulletSim to control object properties. | ||
252 | // Bullet's "CollisionFlags" has more to do with operations on the | ||
253 | // object (if collisions happen, if gravity effects it, ...). | ||
254 | public enum CollisionFlags : uint | ||
255 | { | ||
256 | CF_STATIC_OBJECT = 1 << 0, | ||
257 | CF_KINEMATIC_OBJECT = 1 << 1, | ||
258 | CF_NO_CONTACT_RESPONSE = 1 << 2, | ||
259 | CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, | ||
260 | CF_CHARACTER_OBJECT = 1 << 4, | ||
261 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | ||
262 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | ||
263 | // Following used by BulletSim to control collisions and updates | ||
264 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed | ||
265 | BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level | ||
266 | BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking | ||
267 | BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape | ||
268 | BS_NONE = 0, | ||
269 | BS_ALL = 0x7FFF // collision flags are a signed short | ||
270 | }; | ||
271 | |||
272 | // Values f collisions groups and masks | ||
273 | public enum CollisionFilterGroups : uint | ||
274 | { | ||
275 | // Don't use the bit definitions!! Define the use in a | ||
276 | // filter/mask definition below. This way collision interactions | ||
277 | // are more easily found and debugged. | ||
278 | BNoneGroup = 0, | ||
279 | BDefaultGroup = 1 << 0, // 0001 | ||
280 | BStaticGroup = 1 << 1, // 0002 | ||
281 | BKinematicGroup = 1 << 2, // 0004 | ||
282 | BDebrisGroup = 1 << 3, // 0008 | ||
283 | BSensorTrigger = 1 << 4, // 0010 | ||
284 | BCharacterGroup = 1 << 5, // 0020 | ||
285 | BAllGroup = 0x0007FFF, // collision flags are a signed short | ||
286 | // Filter groups defined by BulletSim | ||
287 | BGroundPlaneGroup = 1 << 8, // 0400 | ||
288 | BTerrainGroup = 1 << 9, // 0800 | ||
289 | BRaycastGroup = 1 << 10, // 1000 | ||
290 | BSolidGroup = 1 << 11, // 2000 | ||
291 | // BLinksetGroup = xx // a linkset proper is either static or dynamic | ||
292 | BLinksetChildGroup = 1 << 12, // 4000 | ||
293 | }; | ||
294 | |||
295 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | ||
296 | // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. | ||
297 | public enum ConstraintParams : int | ||
298 | { | ||
299 | BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 | ||
300 | BT_CONSTRAINT_STOP_ERP, | ||
301 | BT_CONSTRAINT_CFM, | ||
302 | BT_CONSTRAINT_STOP_CFM, | ||
303 | }; | ||
304 | public enum ConstraintParamAxis : int | ||
305 | { | ||
306 | AXIS_LINEAR_X = 0, | ||
307 | AXIS_LINEAR_Y, | ||
308 | AXIS_LINEAR_Z, | ||
309 | AXIS_ANGULAR_X, | ||
310 | AXIS_ANGULAR_Y, | ||
311 | AXIS_ANGULAR_Z, | ||
312 | AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls | ||
313 | AXIS_ANGULAR_ALL, | ||
314 | AXIS_ALL | ||
315 | }; | ||
316 | |||
317 | public abstract class BSAPITemplate | ||
318 | { | ||
319 | // Returns the name of the underlying Bullet engine | ||
320 | public abstract string BulletEngineName { get; } | ||
321 | public abstract string BulletEngineVersion { get; protected set;} | ||
322 | |||
323 | // Initialization and simulation | ||
324 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | ||
325 | int maxCollisions, ref CollisionDesc[] collisionArray, | ||
326 | int maxUpdates, ref EntityProperties[] updateArray | ||
327 | ); | ||
328 | |||
329 | public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
330 | out int updatedEntityCount, out int collidersCount); | ||
331 | |||
332 | public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value); | ||
333 | |||
334 | public abstract void Shutdown(BulletWorld sim); | ||
335 | |||
336 | public abstract bool PushUpdate(BulletBody obj); | ||
337 | |||
338 | // ===================================================================================== | ||
339 | // Mesh, hull, shape and body creation helper routines | ||
340 | public abstract BulletShape CreateMeshShape(BulletWorld world, | ||
341 | int indicesCount, int[] indices, | ||
342 | int verticesCount, float[] vertices ); | ||
343 | |||
344 | public abstract BulletShape CreateGImpactShape(BulletWorld world, | ||
345 | int indicesCount, int[] indices, | ||
346 | int verticesCount, float[] vertices ); | ||
347 | |||
348 | public abstract BulletShape CreateHullShape(BulletWorld world, | ||
349 | int hullCount, float[] hulls); | ||
350 | |||
351 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); | ||
352 | |||
353 | public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | ||
354 | |||
355 | public abstract BulletShape CreateConvexHullShape(BulletWorld world, | ||
356 | int indicesCount, int[] indices, | ||
357 | int verticesCount, float[] vertices ); | ||
358 | |||
359 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); | ||
360 | |||
361 | public abstract bool IsNativeShape(BulletShape shape); | ||
362 | |||
363 | public abstract void SetShapeCollisionMargin(BulletShape shape, float margin); | ||
364 | |||
365 | public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale); | ||
366 | |||
367 | public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree); | ||
368 | |||
369 | public abstract int GetNumberOfCompoundChildren(BulletShape cShape); | ||
370 | |||
371 | public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot); | ||
372 | |||
373 | public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); | ||
374 | |||
375 | public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); | ||
376 | |||
377 | public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); | ||
378 | |||
379 | public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); | ||
380 | |||
381 | public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); | ||
382 | |||
383 | public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id); | ||
384 | |||
385 | public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); | ||
386 | |||
387 | public abstract CollisionObjectTypes GetBodyType(BulletBody obj); | ||
388 | |||
389 | public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); | ||
390 | |||
391 | public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); | ||
392 | |||
393 | public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); | ||
394 | |||
395 | public abstract void DestroyObject(BulletWorld sim, BulletBody obj); | ||
396 | |||
397 | // ===================================================================================== | ||
398 | public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); | ||
399 | |||
400 | public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
401 | float scaleFactor, float collisionMargin); | ||
402 | |||
403 | // ===================================================================================== | ||
404 | // Constraint creation and helper routines | ||
405 | public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
406 | Vector3 frame1loc, Quaternion frame1rot, | ||
407 | Vector3 frame2loc, Quaternion frame2rot, | ||
408 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
409 | |||
410 | public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
411 | Vector3 joinPoint, | ||
412 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
413 | |||
414 | public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, | ||
415 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
416 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); | ||
417 | |||
418 | public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
419 | Vector3 frame1loc, Quaternion frame1rot, | ||
420 | Vector3 frame2loc, Quaternion frame2rot, | ||
421 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
422 | |||
423 | public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
424 | Vector3 pivotinA, Vector3 pivotinB, | ||
425 | Vector3 axisInA, Vector3 axisInB, | ||
426 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
427 | |||
428 | public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
429 | Vector3 frameInAloc, Quaternion frameInArot, | ||
430 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
431 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
432 | |||
433 | public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
434 | Vector3 frameInAloc, Quaternion frameInArot, | ||
435 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
436 | bool disableCollisionsBetweenLinkedBodies); | ||
437 | |||
438 | public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
439 | Vector3 axisInA, Vector3 axisInB, | ||
440 | float ratio, bool disableCollisionsBetweenLinkedBodies); | ||
441 | |||
442 | public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
443 | Vector3 pivotInA, Vector3 pivotInB, | ||
444 | bool disableCollisionsBetweenLinkedBodies); | ||
445 | |||
446 | public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); | ||
447 | |||
448 | public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); | ||
449 | |||
450 | public abstract bool SetFrames(BulletConstraint constrain, | ||
451 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | ||
452 | |||
453 | public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); | ||
454 | |||
455 | public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); | ||
456 | |||
457 | public abstract bool UseFrameOffset(BulletConstraint constrain, float enable); | ||
458 | |||
459 | public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce); | ||
460 | |||
461 | public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); | ||
462 | |||
463 | public const int HINGE_NOT_SPECIFIED = -1; | ||
464 | public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation); | ||
465 | |||
466 | public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse); | ||
467 | |||
468 | public const int SPRING_NOT_SPECIFIED = -1; | ||
469 | public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint); | ||
470 | |||
471 | public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss); | ||
472 | |||
473 | public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping); | ||
474 | |||
475 | public const int SLIDER_LOWER_LIMIT = 0; | ||
476 | public const int SLIDER_UPPER_LIMIT = 1; | ||
477 | public const int SLIDER_LINEAR = 2; | ||
478 | public const int SLIDER_ANGULAR = 3; | ||
479 | public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val); | ||
480 | |||
481 | public const int SLIDER_SET_SOFTNESS = 4; | ||
482 | public const int SLIDER_SET_RESTITUTION = 5; | ||
483 | public const int SLIDER_SET_DAMPING = 6; | ||
484 | public const int SLIDER_SET_DIRECTION = 7; | ||
485 | public const int SLIDER_SET_LIMIT = 8; | ||
486 | public const int SLIDER_SET_ORTHO = 9; | ||
487 | public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); | ||
488 | |||
489 | public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse); | ||
490 | |||
491 | public const int SLIDER_MOTOR_VELOCITY = 10; | ||
492 | public const int SLIDER_MAX_MOTOR_FORCE = 11; | ||
493 | public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val); | ||
494 | |||
495 | public abstract bool CalculateTransforms(BulletConstraint constrain); | ||
496 | |||
497 | public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); | ||
498 | |||
499 | public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain); | ||
500 | |||
501 | // ===================================================================================== | ||
502 | // btCollisionWorld entries | ||
503 | public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj); | ||
504 | |||
505 | public abstract void UpdateAabbs(BulletWorld world); | ||
506 | |||
507 | public abstract bool GetForceUpdateAllAabbs(BulletWorld world); | ||
508 | |||
509 | public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force); | ||
510 | |||
511 | // ===================================================================================== | ||
512 | // btDynamicsWorld entries | ||
513 | // public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot); | ||
514 | public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj); | ||
515 | |||
516 | public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); | ||
517 | |||
518 | public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj); | ||
519 | |||
520 | public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); | ||
521 | |||
522 | public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); | ||
523 | // ===================================================================================== | ||
524 | // btCollisionObject entries | ||
525 | public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain); | ||
526 | |||
527 | public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict); | ||
528 | |||
529 | public abstract bool HasAnisotripicFriction(BulletConstraint constrain); | ||
530 | |||
531 | public abstract void SetContactProcessingThreshold(BulletBody obj, float val); | ||
532 | |||
533 | public abstract float GetContactProcessingThreshold(BulletBody obj); | ||
534 | |||
535 | public abstract bool IsStaticObject(BulletBody obj); | ||
536 | |||
537 | public abstract bool IsKinematicObject(BulletBody obj); | ||
538 | |||
539 | public abstract bool IsStaticOrKinematicObject(BulletBody obj); | ||
540 | |||
541 | public abstract bool HasContactResponse(BulletBody obj); | ||
542 | |||
543 | public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape); | ||
544 | |||
545 | public abstract BulletShape GetCollisionShape(BulletBody obj); | ||
546 | |||
547 | public abstract int GetActivationState(BulletBody obj); | ||
548 | |||
549 | public abstract void SetActivationState(BulletBody obj, int state); | ||
550 | |||
551 | public abstract void SetDeactivationTime(BulletBody obj, float dtime); | ||
552 | |||
553 | public abstract float GetDeactivationTime(BulletBody obj); | ||
554 | |||
555 | public abstract void ForceActivationState(BulletBody obj, ActivationState state); | ||
556 | |||
557 | public abstract void Activate(BulletBody obj, bool forceActivation); | ||
558 | |||
559 | public abstract bool IsActive(BulletBody obj); | ||
560 | |||
561 | public abstract void SetRestitution(BulletBody obj, float val); | ||
562 | |||
563 | public abstract float GetRestitution(BulletBody obj); | ||
564 | |||
565 | public abstract void SetFriction(BulletBody obj, float val); | ||
566 | |||
567 | public abstract float GetFriction(BulletBody obj); | ||
568 | |||
569 | public abstract Vector3 GetPosition(BulletBody obj); | ||
570 | |||
571 | public abstract Quaternion GetOrientation(BulletBody obj); | ||
572 | |||
573 | public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation); | ||
574 | |||
575 | // public abstract IntPtr GetBroadphaseHandle(BulletBody obj); | ||
576 | |||
577 | // public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle); | ||
578 | |||
579 | public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel); | ||
580 | |||
581 | public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel); | ||
582 | |||
583 | public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel); | ||
584 | |||
585 | public abstract float GetHitFraction(BulletBody obj); | ||
586 | |||
587 | public abstract void SetHitFraction(BulletBody obj, float val); | ||
588 | |||
589 | public abstract CollisionFlags GetCollisionFlags(BulletBody obj); | ||
590 | |||
591 | public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
592 | |||
593 | public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
594 | |||
595 | public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
596 | |||
597 | public abstract float GetCcdMotionThreshold(BulletBody obj); | ||
598 | |||
599 | public abstract void SetCcdMotionThreshold(BulletBody obj, float val); | ||
600 | |||
601 | public abstract float GetCcdSweptSphereRadius(BulletBody obj); | ||
602 | |||
603 | public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val); | ||
604 | |||
605 | public abstract IntPtr GetUserPointer(BulletBody obj); | ||
606 | |||
607 | public abstract void SetUserPointer(BulletBody obj, IntPtr val); | ||
608 | |||
609 | // ===================================================================================== | ||
610 | // btRigidBody entries | ||
611 | public abstract void ApplyGravity(BulletBody obj); | ||
612 | |||
613 | public abstract void SetGravity(BulletBody obj, Vector3 val); | ||
614 | |||
615 | public abstract Vector3 GetGravity(BulletBody obj); | ||
616 | |||
617 | public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping); | ||
618 | |||
619 | public abstract void SetLinearDamping(BulletBody obj, float lin_damping); | ||
620 | |||
621 | public abstract void SetAngularDamping(BulletBody obj, float ang_damping); | ||
622 | |||
623 | public abstract float GetLinearDamping(BulletBody obj); | ||
624 | |||
625 | public abstract float GetAngularDamping(BulletBody obj); | ||
626 | |||
627 | public abstract float GetLinearSleepingThreshold(BulletBody obj); | ||
628 | |||
629 | public abstract void ApplyDamping(BulletBody obj, float timeStep); | ||
630 | |||
631 | public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia); | ||
632 | |||
633 | public abstract Vector3 GetLinearFactor(BulletBody obj); | ||
634 | |||
635 | public abstract void SetLinearFactor(BulletBody obj, Vector3 factor); | ||
636 | |||
637 | public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot); | ||
638 | |||
639 | // Add a force to the object as if its mass is one. | ||
640 | public abstract void ApplyCentralForce(BulletBody obj, Vector3 force); | ||
641 | |||
642 | // Set the force being applied to the object as if its mass is one. | ||
643 | public abstract void SetObjectForce(BulletBody obj, Vector3 force); | ||
644 | |||
645 | public abstract Vector3 GetTotalForce(BulletBody obj); | ||
646 | |||
647 | public abstract Vector3 GetTotalTorque(BulletBody obj); | ||
648 | |||
649 | public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj); | ||
650 | |||
651 | public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert); | ||
652 | |||
653 | public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold); | ||
654 | |||
655 | public abstract void ApplyTorque(BulletBody obj, Vector3 torque); | ||
656 | |||
657 | // Apply force at the given point. Will add torque to the object. | ||
658 | public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos); | ||
659 | |||
660 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
661 | public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp); | ||
662 | |||
663 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
664 | public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp); | ||
665 | |||
666 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
667 | public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos); | ||
668 | |||
669 | public abstract void ClearForces(BulletBody obj); | ||
670 | |||
671 | public abstract void ClearAllForces(BulletBody obj); | ||
672 | |||
673 | public abstract void UpdateInertiaTensor(BulletBody obj); | ||
674 | |||
675 | public abstract Vector3 GetLinearVelocity(BulletBody obj); | ||
676 | |||
677 | public abstract Vector3 GetAngularVelocity(BulletBody obj); | ||
678 | |||
679 | public abstract void SetLinearVelocity(BulletBody obj, Vector3 val); | ||
680 | |||
681 | public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity); | ||
682 | |||
683 | public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos); | ||
684 | |||
685 | public abstract void Translate(BulletBody obj, Vector3 trans); | ||
686 | |||
687 | public abstract void UpdateDeactivation(BulletBody obj, float timeStep); | ||
688 | |||
689 | public abstract bool WantsSleeping(BulletBody obj); | ||
690 | |||
691 | public abstract void SetAngularFactor(BulletBody obj, float factor); | ||
692 | |||
693 | public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor); | ||
694 | |||
695 | public abstract Vector3 GetAngularFactor(BulletBody obj); | ||
696 | |||
697 | public abstract bool IsInWorld(BulletWorld world, BulletBody obj); | ||
698 | |||
699 | public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain); | ||
700 | |||
701 | public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain); | ||
702 | |||
703 | public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index); | ||
704 | |||
705 | public abstract int GetNumConstraintRefs(BulletBody obj); | ||
706 | |||
707 | public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask); | ||
708 | |||
709 | // ===================================================================================== | ||
710 | // btCollisionShape entries | ||
711 | |||
712 | public abstract float GetAngularMotionDisc(BulletShape shape); | ||
713 | |||
714 | public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor); | ||
715 | |||
716 | public abstract bool IsPolyhedral(BulletShape shape); | ||
717 | |||
718 | public abstract bool IsConvex2d(BulletShape shape); | ||
719 | |||
720 | public abstract bool IsConvex(BulletShape shape); | ||
721 | |||
722 | public abstract bool IsNonMoving(BulletShape shape); | ||
723 | |||
724 | public abstract bool IsConcave(BulletShape shape); | ||
725 | |||
726 | public abstract bool IsCompound(BulletShape shape); | ||
727 | |||
728 | public abstract bool IsSoftBody(BulletShape shape); | ||
729 | |||
730 | public abstract bool IsInfinite(BulletShape shape); | ||
731 | |||
732 | public abstract void SetLocalScaling(BulletShape shape, Vector3 scale); | ||
733 | |||
734 | public abstract Vector3 GetLocalScaling(BulletShape shape); | ||
735 | |||
736 | public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass); | ||
737 | |||
738 | public abstract int GetShapeType(BulletShape shape); | ||
739 | |||
740 | public abstract void SetMargin(BulletShape shape, float val); | ||
741 | |||
742 | public abstract float GetMargin(BulletShape shape); | ||
743 | |||
744 | // ===================================================================================== | ||
745 | // Debugging | ||
746 | public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { } | ||
747 | |||
748 | public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { } | ||
749 | |||
750 | public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { } | ||
751 | |||
752 | public virtual void DumpActivationInfo(BulletWorld sim) { } | ||
753 | |||
754 | public virtual void DumpAllInfo(BulletWorld sim) { } | ||
755 | |||
756 | public virtual void DumpPhysicsStatistics(BulletWorld sim) { } | ||
757 | |||
758 | public virtual void ResetBroadphasePool(BulletWorld sim) { } | ||
759 | |||
760 | public virtual void ResetConstraintSolver(BulletWorld sim) { } | ||
761 | |||
762 | }; | ||
763 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs new file mode 100644 index 0000000..9c3f160 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs | |||
@@ -0,0 +1,813 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | using OMV = OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public sealed class BSCharacter : BSPhysObject | ||
38 | { | ||
39 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
40 | private static readonly string LogHeader = "[BULLETS CHAR]"; | ||
41 | |||
42 | // private bool _stopped; | ||
43 | private OMV.Vector3 _size; | ||
44 | private bool _grabbed; | ||
45 | private bool _selected; | ||
46 | private float _mass; | ||
47 | private float _avatarVolume; | ||
48 | private float _collisionScore; | ||
49 | private OMV.Vector3 _acceleration; | ||
50 | private int _physicsActorType; | ||
51 | private bool _isPhysical; | ||
52 | private bool _flying; | ||
53 | private bool _setAlwaysRun; | ||
54 | private bool _throttleUpdates; | ||
55 | private bool _floatOnWater; | ||
56 | private OMV.Vector3 _rotationalVelocity; | ||
57 | private bool _kinematic; | ||
58 | private float _buoyancy; | ||
59 | |||
60 | private BSActorAvatarMove m_moveActor; | ||
61 | private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; | ||
62 | |||
63 | private OMV.Vector3 _PIDTarget; | ||
64 | private float _PIDTau; | ||
65 | |||
66 | // public override OMV.Vector3 RawVelocity | ||
67 | // { get { return base.RawVelocity; } | ||
68 | // set { | ||
69 | // if (value != base.RawVelocity) | ||
70 | // Util.PrintCallStack(); | ||
71 | // Console.WriteLine("Set rawvel to {0}", value); | ||
72 | // base.RawVelocity = value; } | ||
73 | // } | ||
74 | |||
75 | // Avatars are always complete (in the physics engine sense) | ||
76 | public override bool IsIncomplete { get { return false; } } | ||
77 | |||
78 | public BSCharacter( | ||
79 | uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying) | ||
80 | |||
81 | : base(parent_scene, localID, avName, "BSCharacter") | ||
82 | { | ||
83 | _physicsActorType = (int)ActorTypes.Agent; | ||
84 | RawPosition = pos; | ||
85 | |||
86 | _flying = isFlying; | ||
87 | RawOrientation = OMV.Quaternion.Identity; | ||
88 | RawVelocity = vel; | ||
89 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | ||
90 | Friction = BSParam.AvatarStandingFriction; | ||
91 | Density = BSParam.AvatarDensity; | ||
92 | |||
93 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
94 | // replace with the default values. | ||
95 | _size = size; | ||
96 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
97 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
98 | |||
99 | // The dimensions of the physical capsule are kept in the scale. | ||
100 | // Physics creates a unit capsule which is scaled by the physics engine. | ||
101 | Scale = ComputeAvatarScale(_size); | ||
102 | // set _avatarVolume and _mass based on capsule size, _density and Scale | ||
103 | ComputeAvatarVolumeAndMass(); | ||
104 | |||
105 | DetailLog( | ||
106 | "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}", | ||
107 | LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel); | ||
108 | |||
109 | // do actual creation in taint time | ||
110 | PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate() | ||
111 | { | ||
112 | DetailLog("{0},BSCharacter.create,taint", LocalID); | ||
113 | |||
114 | // New body and shape into PhysBody and PhysShape | ||
115 | PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); | ||
116 | |||
117 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
118 | // the avatar seeking to reach the motor's target speed. | ||
119 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
120 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
121 | m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); | ||
122 | PhysicalActors.Add(AvatarMoveActorName, m_moveActor); | ||
123 | |||
124 | SetPhysicalProperties(); | ||
125 | |||
126 | IsInitialized = true; | ||
127 | }); | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | // called when this character is being destroyed and the resources should be released | ||
132 | public override void Destroy() | ||
133 | { | ||
134 | IsInitialized = false; | ||
135 | |||
136 | base.Destroy(); | ||
137 | |||
138 | DetailLog("{0},BSCharacter.Destroy", LocalID); | ||
139 | PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate() | ||
140 | { | ||
141 | PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); | ||
142 | PhysBody.Clear(); | ||
143 | PhysShape.Dereference(PhysScene); | ||
144 | PhysShape = new BSShapeNull(); | ||
145 | }); | ||
146 | } | ||
147 | |||
148 | private void SetPhysicalProperties() | ||
149 | { | ||
150 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); | ||
151 | |||
152 | ForcePosition = RawPosition; | ||
153 | |||
154 | // Set the velocity | ||
155 | if (m_moveActor != null) | ||
156 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); | ||
157 | |||
158 | ForceVelocity = RawVelocity; | ||
159 | TargetVelocity = RawVelocity; | ||
160 | |||
161 | // This will enable or disable the flying buoyancy of the avatar. | ||
162 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | ||
163 | Flying = _flying; | ||
164 | |||
165 | PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); | ||
166 | PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); | ||
167 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); | ||
168 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | ||
169 | if (BSParam.CcdMotionThreshold > 0f) | ||
170 | { | ||
171 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | ||
172 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | ||
173 | } | ||
174 | |||
175 | UpdatePhysicalMassProperties(RawMass, false); | ||
176 | |||
177 | // Make so capsule does not fall over | ||
178 | PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); | ||
179 | |||
180 | // The avatar mover sets some parameters. | ||
181 | PhysicalActors.Refresh(); | ||
182 | |||
183 | PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); | ||
184 | |||
185 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); | ||
186 | |||
187 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | ||
188 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); | ||
189 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); | ||
190 | |||
191 | // Do this after the object has been added to the world | ||
192 | if (BSParam.AvatarToAvatarCollisionsByDefault) | ||
193 | PhysBody.collisionType = CollisionType.Avatar; | ||
194 | else | ||
195 | PhysBody.collisionType = CollisionType.PhantomToOthersAvatar; | ||
196 | |||
197 | PhysBody.ApplyCollisionMask(PhysScene); | ||
198 | } | ||
199 | |||
200 | public override void RequestPhysicsterseUpdate() | ||
201 | { | ||
202 | base.RequestPhysicsterseUpdate(); | ||
203 | } | ||
204 | |||
205 | // No one calls this method so I don't know what it could possibly mean | ||
206 | public override bool Stopped { get { return false; } } | ||
207 | |||
208 | public override OMV.Vector3 Size { | ||
209 | get | ||
210 | { | ||
211 | // Avatar capsule size is kept in the scale parameter. | ||
212 | return _size; | ||
213 | } | ||
214 | |||
215 | set { | ||
216 | // This is how much the avatar size is changing. Positive means getting bigger. | ||
217 | // The avatar altitude must be adjusted for this change. | ||
218 | float heightChange = value.Z - _size.Z; | ||
219 | |||
220 | _size = value; | ||
221 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
222 | // replace with the default values. | ||
223 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
224 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
225 | |||
226 | Scale = ComputeAvatarScale(_size); | ||
227 | ComputeAvatarVolumeAndMass(); | ||
228 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
229 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | ||
230 | |||
231 | PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate() | ||
232 | { | ||
233 | if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) | ||
234 | { | ||
235 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); | ||
236 | UpdatePhysicalMassProperties(RawMass, true); | ||
237 | |||
238 | // Adjust the avatar's position to account for the increase/decrease in size | ||
239 | ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); | ||
240 | |||
241 | // Make sure this change appears as a property update event | ||
242 | PhysScene.PE.PushUpdate(PhysBody); | ||
243 | } | ||
244 | }); | ||
245 | |||
246 | } | ||
247 | } | ||
248 | |||
249 | public override PrimitiveBaseShape Shape | ||
250 | { | ||
251 | set { BaseShape = value; } | ||
252 | } | ||
253 | |||
254 | public override bool Grabbed { | ||
255 | set { _grabbed = value; } | ||
256 | } | ||
257 | public override bool Selected { | ||
258 | set { _selected = value; } | ||
259 | } | ||
260 | public override bool IsSelected | ||
261 | { | ||
262 | get { return _selected; } | ||
263 | } | ||
264 | public override void CrossingFailure() { return; } | ||
265 | public override void link(PhysicsActor obj) { return; } | ||
266 | public override void delink() { return; } | ||
267 | |||
268 | // Set motion values to zero. | ||
269 | // Do it to the properties so the values get set in the physics engine. | ||
270 | // Push the setting of the values to the viewer. | ||
271 | // Called at taint time! | ||
272 | public override void ZeroMotion(bool inTaintTime) | ||
273 | { | ||
274 | RawVelocity = OMV.Vector3.Zero; | ||
275 | _acceleration = OMV.Vector3.Zero; | ||
276 | _rotationalVelocity = OMV.Vector3.Zero; | ||
277 | |||
278 | // Zero some other properties directly into the physics engine | ||
279 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() | ||
280 | { | ||
281 | if (PhysBody.HasPhysicalBody) | ||
282 | PhysScene.PE.ClearAllForces(PhysBody); | ||
283 | }); | ||
284 | } | ||
285 | |||
286 | public override void ZeroAngularMotion(bool inTaintTime) | ||
287 | { | ||
288 | _rotationalVelocity = OMV.Vector3.Zero; | ||
289 | |||
290 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() | ||
291 | { | ||
292 | if (PhysBody.HasPhysicalBody) | ||
293 | { | ||
294 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); | ||
295 | PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); | ||
296 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
297 | PhysScene.PE.ClearForces(PhysBody); | ||
298 | } | ||
299 | }); | ||
300 | } | ||
301 | |||
302 | |||
303 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | ||
304 | |||
305 | public override OMV.Vector3 Position { | ||
306 | get { | ||
307 | // Don't refetch the position because this function is called a zillion times | ||
308 | // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); | ||
309 | return RawPosition; | ||
310 | } | ||
311 | set { | ||
312 | RawPosition = value; | ||
313 | |||
314 | PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate() | ||
315 | { | ||
316 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); | ||
317 | PositionSanityCheck(); | ||
318 | ForcePosition = RawPosition; | ||
319 | }); | ||
320 | } | ||
321 | } | ||
322 | public override OMV.Vector3 ForcePosition { | ||
323 | get { | ||
324 | RawPosition = PhysScene.PE.GetPosition(PhysBody); | ||
325 | return RawPosition; | ||
326 | } | ||
327 | set { | ||
328 | RawPosition = value; | ||
329 | if (PhysBody.HasPhysicalBody) | ||
330 | { | ||
331 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | |||
337 | // Check that the current position is sane and, if not, modify the position to make it so. | ||
338 | // Check for being below terrain or on water. | ||
339 | // Returns 'true' of the position was made sane by some action. | ||
340 | private bool PositionSanityCheck() | ||
341 | { | ||
342 | bool ret = false; | ||
343 | |||
344 | // TODO: check for out of bounds | ||
345 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | ||
346 | { | ||
347 | // The character is out of the known/simulated area. | ||
348 | // Force the avatar position to be within known. ScenePresence will use the position | ||
349 | // plus the velocity to decide if the avatar is moving out of the region. | ||
350 | RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); | ||
351 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); | ||
352 | return true; | ||
353 | } | ||
354 | |||
355 | // If below the ground, move the avatar up | ||
356 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | ||
357 | if (Position.Z < terrainHeight) | ||
358 | { | ||
359 | DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); | ||
360 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters); | ||
361 | ret = true; | ||
362 | } | ||
363 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
364 | { | ||
365 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); | ||
366 | if (Position.Z < waterHeight) | ||
367 | { | ||
368 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight); | ||
369 | ret = true; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | return ret; | ||
374 | } | ||
375 | |||
376 | // A version of the sanity check that also makes sure a new position value is | ||
377 | // pushed back to the physics engine. This routine would be used by anyone | ||
378 | // who is not already pushing the value. | ||
379 | private bool PositionSanityCheck(bool inTaintTime) | ||
380 | { | ||
381 | bool ret = false; | ||
382 | if (PositionSanityCheck()) | ||
383 | { | ||
384 | // The new position value must be pushed into the physics engine but we can't | ||
385 | // just assign to "Position" because of potential call loops. | ||
386 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate() | ||
387 | { | ||
388 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); | ||
389 | ForcePosition = RawPosition; | ||
390 | }); | ||
391 | ret = true; | ||
392 | } | ||
393 | return ret; | ||
394 | } | ||
395 | |||
396 | public override float Mass { get { return _mass; } } | ||
397 | |||
398 | // used when we only want this prim's mass and not the linkset thing | ||
399 | public override float RawMass { | ||
400 | get {return _mass; } | ||
401 | } | ||
402 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | ||
403 | { | ||
404 | OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); | ||
405 | PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); | ||
406 | } | ||
407 | |||
408 | public override OMV.Vector3 Force { | ||
409 | get { return RawForce; } | ||
410 | set { | ||
411 | RawForce = value; | ||
412 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | ||
413 | PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate() | ||
414 | { | ||
415 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); | ||
416 | if (PhysBody.HasPhysicalBody) | ||
417 | PhysScene.PE.SetObjectForce(PhysBody, RawForce); | ||
418 | }); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | // Avatars don't do vehicles | ||
423 | public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } | ||
424 | public override void VehicleFloatParam(int param, float value) { } | ||
425 | public override void VehicleVectorParam(int param, OMV.Vector3 value) {} | ||
426 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } | ||
427 | public override void VehicleFlags(int param, bool remove) { } | ||
428 | |||
429 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||
430 | public override void SetVolumeDetect(int param) { return; } | ||
431 | public override bool IsVolumeDetect { get { return false; } } | ||
432 | |||
433 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | ||
434 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | ||
435 | |||
436 | // Sets the target in the motor. This starts the changing of the avatar's velocity. | ||
437 | public override OMV.Vector3 TargetVelocity | ||
438 | { | ||
439 | get | ||
440 | { | ||
441 | return base.m_targetVelocity; | ||
442 | } | ||
443 | set | ||
444 | { | ||
445 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | ||
446 | m_targetVelocity = value; | ||
447 | OMV.Vector3 targetVel = value; | ||
448 | if (_setAlwaysRun && !_flying) | ||
449 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f); | ||
450 | |||
451 | if (m_moveActor != null) | ||
452 | m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); | ||
453 | } | ||
454 | } | ||
455 | // Directly setting velocity means this is what the user really wants now. | ||
456 | public override OMV.Vector3 Velocity { | ||
457 | get { return RawVelocity; } | ||
458 | set { | ||
459 | RawVelocity = value; | ||
460 | OMV.Vector3 vel = RawVelocity; | ||
461 | |||
462 | DetailLog("{0}: set Velocity = {1}", LocalID, value); | ||
463 | |||
464 | PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate() | ||
465 | { | ||
466 | if (m_moveActor != null) | ||
467 | m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */); | ||
468 | |||
469 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel); | ||
470 | ForceVelocity = vel; | ||
471 | }); | ||
472 | } | ||
473 | } | ||
474 | |||
475 | public override OMV.Vector3 ForceVelocity { | ||
476 | get { return RawVelocity; } | ||
477 | set { | ||
478 | PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | ||
479 | // Util.PrintCallStack(); | ||
480 | DetailLog("{0}: set ForceVelocity = {1}", LocalID, value); | ||
481 | |||
482 | RawVelocity = value; | ||
483 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); | ||
484 | PhysScene.PE.Activate(PhysBody, true); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | public override OMV.Vector3 Torque { | ||
489 | get { return RawTorque; } | ||
490 | set { RawTorque = value; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | public override float CollisionScore { | ||
495 | get { return _collisionScore; } | ||
496 | set { _collisionScore = value; | ||
497 | } | ||
498 | } | ||
499 | public override OMV.Vector3 Acceleration { | ||
500 | get { return _acceleration; } | ||
501 | set { _acceleration = value; } | ||
502 | } | ||
503 | public override OMV.Quaternion Orientation { | ||
504 | get { return RawOrientation; } | ||
505 | set { | ||
506 | // Orientation is set zillions of times when an avatar is walking. It's like | ||
507 | // the viewer doesn't trust us. | ||
508 | if (RawOrientation != value) | ||
509 | { | ||
510 | RawOrientation = value; | ||
511 | PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate() | ||
512 | { | ||
513 | // Bullet assumes we know what we are doing when forcing orientation | ||
514 | // so it lets us go against all the rules and just compensates for them later. | ||
515 | // This forces rotation to be only around the Z axis and doesn't change any of the other axis. | ||
516 | // This keeps us from flipping the capsule over which the veiwer does not understand. | ||
517 | float oRoll, oPitch, oYaw; | ||
518 | RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); | ||
519 | OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); | ||
520 | // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", | ||
521 | // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation, | ||
522 | // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); | ||
523 | ForceOrientation = trimmedOrientation; | ||
524 | }); | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | // Go directly to Bullet to get/set the value. | ||
529 | public override OMV.Quaternion ForceOrientation | ||
530 | { | ||
531 | get | ||
532 | { | ||
533 | RawOrientation = PhysScene.PE.GetOrientation(PhysBody); | ||
534 | return RawOrientation; | ||
535 | } | ||
536 | set | ||
537 | { | ||
538 | RawOrientation = value; | ||
539 | if (PhysBody.HasPhysicalBody) | ||
540 | { | ||
541 | // RawPosition = PhysicsScene.PE.GetPosition(BSBody); | ||
542 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); | ||
543 | } | ||
544 | } | ||
545 | } | ||
546 | public override int PhysicsActorType { | ||
547 | get { return _physicsActorType; } | ||
548 | set { _physicsActorType = value; | ||
549 | } | ||
550 | } | ||
551 | public override bool IsPhysical { | ||
552 | get { return _isPhysical; } | ||
553 | set { _isPhysical = value; | ||
554 | } | ||
555 | } | ||
556 | public override bool IsSolid { | ||
557 | get { return true; } | ||
558 | } | ||
559 | public override bool IsStatic { | ||
560 | get { return false; } | ||
561 | } | ||
562 | public override bool IsPhysicallyActive { | ||
563 | get { return true; } | ||
564 | } | ||
565 | public override bool Flying { | ||
566 | get { return _flying; } | ||
567 | set { | ||
568 | _flying = value; | ||
569 | |||
570 | // simulate flying by changing the effect of gravity | ||
571 | Buoyancy = ComputeBuoyancyFromFlying(_flying); | ||
572 | } | ||
573 | } | ||
574 | // Flying is implimented by changing the avatar's buoyancy. | ||
575 | // Would this be done better with a vehicle type? | ||
576 | private float ComputeBuoyancyFromFlying(bool ifFlying) { | ||
577 | return ifFlying ? 1f : 0f; | ||
578 | } | ||
579 | public override bool | ||
580 | SetAlwaysRun { | ||
581 | get { return _setAlwaysRun; } | ||
582 | set { _setAlwaysRun = value; } | ||
583 | } | ||
584 | public override bool ThrottleUpdates { | ||
585 | get { return _throttleUpdates; } | ||
586 | set { _throttleUpdates = value; } | ||
587 | } | ||
588 | public override bool FloatOnWater { | ||
589 | set { | ||
590 | _floatOnWater = value; | ||
591 | PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate() | ||
592 | { | ||
593 | if (PhysBody.HasPhysicalBody) | ||
594 | { | ||
595 | if (_floatOnWater) | ||
596 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | ||
597 | else | ||
598 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | ||
599 | } | ||
600 | }); | ||
601 | } | ||
602 | } | ||
603 | public override OMV.Vector3 RotationalVelocity { | ||
604 | get { return _rotationalVelocity; } | ||
605 | set { _rotationalVelocity = value; } | ||
606 | } | ||
607 | public override OMV.Vector3 ForceRotationalVelocity { | ||
608 | get { return _rotationalVelocity; } | ||
609 | set { _rotationalVelocity = value; } | ||
610 | } | ||
611 | public override bool Kinematic { | ||
612 | get { return _kinematic; } | ||
613 | set { _kinematic = value; } | ||
614 | } | ||
615 | // neg=fall quickly, 0=1g, 1=0g, pos=float up | ||
616 | public override float Buoyancy { | ||
617 | get { return _buoyancy; } | ||
618 | set { _buoyancy = value; | ||
619 | PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate() | ||
620 | { | ||
621 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
622 | ForceBuoyancy = _buoyancy; | ||
623 | }); | ||
624 | } | ||
625 | } | ||
626 | public override float ForceBuoyancy { | ||
627 | get { return _buoyancy; } | ||
628 | set { | ||
629 | PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | ||
630 | |||
631 | _buoyancy = value; | ||
632 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
633 | // Buoyancy is faked by changing the gravity applied to the object | ||
634 | float grav = BSParam.Gravity * (1f - _buoyancy); | ||
635 | Gravity = new OMV.Vector3(0f, 0f, grav); | ||
636 | if (PhysBody.HasPhysicalBody) | ||
637 | PhysScene.PE.SetGravity(PhysBody, Gravity); | ||
638 | } | ||
639 | } | ||
640 | |||
641 | // Used for MoveTo | ||
642 | public override OMV.Vector3 PIDTarget { | ||
643 | set { _PIDTarget = value; } | ||
644 | } | ||
645 | |||
646 | public override bool PIDActive { get; set; } | ||
647 | |||
648 | public override float PIDTau { | ||
649 | set { _PIDTau = value; } | ||
650 | } | ||
651 | |||
652 | public override void AddForce(OMV.Vector3 force, bool pushforce) | ||
653 | { | ||
654 | // Since this force is being applied in only one step, make this a force per second. | ||
655 | OMV.Vector3 addForce = force / PhysScene.LastTimeStep; | ||
656 | AddForce(addForce, pushforce, false); | ||
657 | } | ||
658 | public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
659 | if (force.IsFinite()) | ||
660 | { | ||
661 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | ||
662 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); | ||
663 | |||
664 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate() | ||
665 | { | ||
666 | // Bullet adds this central force to the total force for this tick | ||
667 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); | ||
668 | if (PhysBody.HasPhysicalBody) | ||
669 | { | ||
670 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); | ||
671 | } | ||
672 | }); | ||
673 | } | ||
674 | else | ||
675 | { | ||
676 | m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID); | ||
677 | return; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
682 | } | ||
683 | public override void SetMomentum(OMV.Vector3 momentum) { | ||
684 | } | ||
685 | |||
686 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) | ||
687 | { | ||
688 | OMV.Vector3 newScale = size; | ||
689 | |||
690 | // Bullet's capsule total height is the "passed height + radius * 2"; | ||
691 | // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) | ||
692 | // The number we pass in for 'scaling' is the multiplier to get that base | ||
693 | // shape to be the size desired. | ||
694 | // So, when creating the scale for the avatar height, we take the passed height | ||
695 | // (size.Z) and remove the caps. | ||
696 | // An oddity of the Bullet capsule implementation is that it presumes the Y | ||
697 | // dimension is the radius of the capsule. Even though some of the code allows | ||
698 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. | ||
699 | |||
700 | // Scale is multiplier of radius with one of "0.5" | ||
701 | |||
702 | float heightAdjust = BSParam.AvatarHeightMidFudge; | ||
703 | if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) | ||
704 | { | ||
705 | const float AVATAR_LOW = 1.1f; | ||
706 | const float AVATAR_MID = 1.775f; // 1.87f | ||
707 | const float AVATAR_HI = 2.45f; | ||
708 | // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m. | ||
709 | float midHeightOffset = size.Z - AVATAR_MID; | ||
710 | if (midHeightOffset < 0f) | ||
711 | { | ||
712 | // Small avatar. Add the adjustment based on the distance from midheight | ||
713 | heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge; | ||
714 | } | ||
715 | else | ||
716 | { | ||
717 | // Large avatar. Add the adjustment based on the distance from midheight | ||
718 | heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge; | ||
719 | } | ||
720 | } | ||
721 | if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) | ||
722 | { | ||
723 | newScale.X = size.X / 2f; | ||
724 | newScale.Y = size.Y / 2f; | ||
725 | // The total scale height is the central cylindar plus the caps on the two ends. | ||
726 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; | ||
727 | } | ||
728 | else | ||
729 | { | ||
730 | newScale.Z = size.Z + heightAdjust; | ||
731 | } | ||
732 | // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); | ||
733 | |||
734 | // If smaller than the endcaps, just fake like we're almost that small | ||
735 | if (newScale.Z < 0) | ||
736 | newScale.Z = 0.1f; | ||
737 | |||
738 | DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}", | ||
739 | LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale); | ||
740 | |||
741 | return newScale; | ||
742 | } | ||
743 | |||
744 | // set _avatarVolume and _mass based on capsule size, _density and Scale | ||
745 | private void ComputeAvatarVolumeAndMass() | ||
746 | { | ||
747 | _avatarVolume = (float)( | ||
748 | Math.PI | ||
749 | * Size.X / 2f | ||
750 | * Size.Y / 2f // the area of capsule cylinder | ||
751 | * Size.Z // times height of capsule cylinder | ||
752 | + 1.33333333f | ||
753 | * Math.PI | ||
754 | * Size.X / 2f | ||
755 | * Math.Min(Size.X, Size.Y) / 2 | ||
756 | * Size.Y / 2f // plus the volume of the capsule end caps | ||
757 | ); | ||
758 | _mass = Density * BSParam.DensityScaleFactor * _avatarVolume; | ||
759 | } | ||
760 | |||
761 | // The physics engine says that properties have updated. Update same and inform | ||
762 | // the world that things have changed. | ||
763 | public override void UpdateProperties(EntityProperties entprop) | ||
764 | { | ||
765 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. | ||
766 | TriggerPreUpdatePropertyAction(ref entprop); | ||
767 | |||
768 | RawPosition = entprop.Position; | ||
769 | RawOrientation = entprop.Rotation; | ||
770 | |||
771 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar | ||
772 | // and will send agent updates to the clients if velocity changes by more than | ||
773 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many | ||
774 | // extra updates. | ||
775 | // | ||
776 | // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to | ||
777 | // avatar movement rather than removes it. The larger the threshold, the bigger the jitter. | ||
778 | // This is most noticeable in level flight and can be seen with | ||
779 | // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower | ||
780 | // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update | ||
781 | // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?) | ||
782 | // has not yet been identified. | ||
783 | // | ||
784 | // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra | ||
785 | // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients(). | ||
786 | // if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) | ||
787 | RawVelocity = entprop.Velocity; | ||
788 | |||
789 | _acceleration = entprop.Acceleration; | ||
790 | _rotationalVelocity = entprop.RotationalVelocity; | ||
791 | |||
792 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | ||
793 | if (PositionSanityCheck(true)) | ||
794 | { | ||
795 | DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition); | ||
796 | entprop.Position = RawPosition; | ||
797 | } | ||
798 | |||
799 | // remember the current and last set values | ||
800 | LastEntityProperties = CurrentEntityProperties; | ||
801 | CurrentEntityProperties = entprop; | ||
802 | |||
803 | // Tell the linkset about value changes | ||
804 | // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); | ||
805 | |||
806 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | ||
807 | // PhysScene.PostUpdate(this); | ||
808 | |||
809 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
810 | LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); | ||
811 | } | ||
812 | } | ||
813 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs new file mode 100755 index 0000000..b47e9a8 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs | |||
@@ -0,0 +1,144 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | |||
35 | public abstract class BSConstraint : IDisposable | ||
36 | { | ||
37 | private static string LogHeader = "[BULLETSIM CONSTRAINT]"; | ||
38 | |||
39 | protected BulletWorld m_world; | ||
40 | protected BSScene PhysicsScene; | ||
41 | protected BulletBody m_body1; | ||
42 | protected BulletBody m_body2; | ||
43 | protected BulletConstraint m_constraint; | ||
44 | protected bool m_enabled = false; | ||
45 | |||
46 | public BulletBody Body1 { get { return m_body1; } } | ||
47 | public BulletBody Body2 { get { return m_body2; } } | ||
48 | public BulletConstraint Constraint { get { return m_constraint; } } | ||
49 | public abstract ConstraintType Type { get; } | ||
50 | public bool IsEnabled { get { return m_enabled; } } | ||
51 | |||
52 | public BSConstraint(BulletWorld world) | ||
53 | { | ||
54 | m_world = world; | ||
55 | PhysicsScene = m_world.physicsScene; | ||
56 | } | ||
57 | |||
58 | public virtual void Dispose() | ||
59 | { | ||
60 | if (m_enabled) | ||
61 | { | ||
62 | m_enabled = false; | ||
63 | if (m_constraint.HasPhysicalConstraint) | ||
64 | { | ||
65 | bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); | ||
66 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", | ||
67 | m_body1.ID, | ||
68 | m_body1.ID, m_body1.AddrString, | ||
69 | m_body2.ID, m_body2.AddrString, | ||
70 | success); | ||
71 | m_constraint.Clear(); | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | public virtual bool SetLinearLimits(Vector3 low, Vector3 high) | ||
77 | { | ||
78 | bool ret = false; | ||
79 | if (m_enabled) | ||
80 | { | ||
81 | m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high); | ||
82 | ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); | ||
83 | } | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | public virtual bool SetAngularLimits(Vector3 low, Vector3 high) | ||
88 | { | ||
89 | bool ret = false; | ||
90 | if (m_enabled) | ||
91 | { | ||
92 | m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high); | ||
93 | ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); | ||
94 | } | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | public virtual bool SetSolverIterations(float cnt) | ||
99 | { | ||
100 | bool ret = false; | ||
101 | if (m_enabled) | ||
102 | { | ||
103 | PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt); | ||
104 | ret = true; | ||
105 | } | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | public virtual bool CalculateTransforms() | ||
110 | { | ||
111 | bool ret = false; | ||
112 | if (m_enabled) | ||
113 | { | ||
114 | // Recompute the internal transforms | ||
115 | PhysicsScene.PE.CalculateTransforms(m_constraint); | ||
116 | ret = true; | ||
117 | } | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | // Reset this constraint making sure it has all its internal structures | ||
122 | // recomputed and is enabled and ready to go. | ||
123 | public virtual bool RecomputeConstraintVariables(float mass) | ||
124 | { | ||
125 | bool ret = false; | ||
126 | if (m_enabled) | ||
127 | { | ||
128 | ret = CalculateTransforms(); | ||
129 | if (ret) | ||
130 | { | ||
131 | // Setting an object's mass to zero (making it static like when it's selected) | ||
132 | // automatically disables the constraints. | ||
133 | // If the link is enabled, be sure to set the constraint itself to enabled. | ||
134 | PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true)); | ||
135 | } | ||
136 | else | ||
137 | { | ||
138 | m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID); | ||
139 | } | ||
140 | } | ||
141 | return ret; | ||
142 | } | ||
143 | } | ||
144 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs new file mode 100755 index 0000000..7fcb75c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs | |||
@@ -0,0 +1,180 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | |||
35 | public class BSConstraint6Dof : BSConstraint | ||
36 | { | ||
37 | private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; | ||
38 | |||
39 | public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } | ||
40 | |||
41 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world) | ||
42 | { | ||
43 | m_body1 = obj1; | ||
44 | m_body2 = obj2; | ||
45 | m_enabled = false; | ||
46 | } | ||
47 | |||
48 | // Create a btGeneric6DofConstraint | ||
49 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
50 | Vector3 frame1, Quaternion frame1rot, | ||
51 | Vector3 frame2, Quaternion frame2rot, | ||
52 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
53 | : base(world) | ||
54 | { | ||
55 | m_body1 = obj1; | ||
56 | m_body2 = obj2; | ||
57 | m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2, | ||
58 | frame1, frame1rot, | ||
59 | frame2, frame2rot, | ||
60 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | ||
61 | m_enabled = true; | ||
62 | PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
63 | m_body1.ID, world.worldID, | ||
64 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); | ||
65 | PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", | ||
66 | m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | ||
67 | } | ||
68 | |||
69 | // 6 Dof constraint based on a midpoint between the two constrained bodies | ||
70 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
71 | Vector3 joinPoint, | ||
72 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
73 | : base(world) | ||
74 | { | ||
75 | m_body1 = obj1; | ||
76 | m_body2 = obj2; | ||
77 | if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) | ||
78 | { | ||
79 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
80 | BSScene.DetailLogZero, world.worldID, | ||
81 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); | ||
82 | world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
83 | LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); | ||
84 | m_enabled = false; | ||
85 | } | ||
86 | else | ||
87 | { | ||
88 | m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, | ||
89 | joinPoint, | ||
90 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | ||
91 | |||
92 | PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", | ||
93 | m_body1.ID, world.worldID, m_constraint.AddrString, | ||
94 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); | ||
95 | |||
96 | if (!m_constraint.HasPhysicalConstraint) | ||
97 | { | ||
98 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", | ||
99 | LogHeader, obj1.ID, obj2.ID); | ||
100 | m_enabled = false; | ||
101 | } | ||
102 | else | ||
103 | { | ||
104 | m_enabled = true; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object | ||
110 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, | ||
111 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) | ||
112 | : base(world) | ||
113 | { | ||
114 | m_body1 = obj1; | ||
115 | m_body2 = obj1; // Look out for confusion down the road | ||
116 | m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, | ||
117 | frameInBloc, frameInBrot, | ||
118 | useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); | ||
119 | m_enabled = true; | ||
120 | PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", | ||
121 | m_body1.ID, world.worldID, obj1.ID, obj1.AddrString); | ||
122 | PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}", | ||
123 | m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); | ||
124 | } | ||
125 | |||
126 | public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) | ||
127 | { | ||
128 | bool ret = false; | ||
129 | if (m_enabled) | ||
130 | { | ||
131 | PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot); | ||
132 | ret = true; | ||
133 | } | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | public bool SetCFMAndERP(float cfm, float erp) | ||
138 | { | ||
139 | bool ret = false; | ||
140 | if (m_enabled) | ||
141 | { | ||
142 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | ||
143 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); | ||
144 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | ||
145 | ret = true; | ||
146 | } | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | public bool UseFrameOffset(bool useOffset) | ||
151 | { | ||
152 | bool ret = false; | ||
153 | float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | ||
154 | if (m_enabled) | ||
155 | ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff); | ||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce) | ||
160 | { | ||
161 | bool ret = false; | ||
162 | float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | ||
163 | if (m_enabled) | ||
164 | { | ||
165 | ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce); | ||
166 | m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", | ||
167 | BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); | ||
168 | } | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | public bool SetBreakingImpulseThreshold(float threshold) | ||
173 | { | ||
174 | bool ret = false; | ||
175 | if (m_enabled) | ||
176 | ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold); | ||
177 | return ret; | ||
178 | } | ||
179 | } | ||
180 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs new file mode 100755 index 0000000..5c8d94e --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs | |||
@@ -0,0 +1,181 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using log4net; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | |||
36 | public sealed class BSConstraintCollection : IDisposable | ||
37 | { | ||
38 | // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
39 | // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; | ||
40 | |||
41 | delegate bool ConstraintAction(BSConstraint constrain); | ||
42 | |||
43 | private List<BSConstraint> m_constraints; | ||
44 | private BulletWorld m_world; | ||
45 | |||
46 | public BSConstraintCollection(BulletWorld world) | ||
47 | { | ||
48 | m_world = world; | ||
49 | m_constraints = new List<BSConstraint>(); | ||
50 | } | ||
51 | |||
52 | public void Dispose() | ||
53 | { | ||
54 | this.Clear(); | ||
55 | } | ||
56 | |||
57 | public void Clear() | ||
58 | { | ||
59 | lock (m_constraints) | ||
60 | { | ||
61 | foreach (BSConstraint cons in m_constraints) | ||
62 | { | ||
63 | cons.Dispose(); | ||
64 | } | ||
65 | m_constraints.Clear(); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | public bool AddConstraint(BSConstraint cons) | ||
70 | { | ||
71 | lock (m_constraints) | ||
72 | { | ||
73 | // There is only one constraint between any bodies. Remove any old just to make sure. | ||
74 | RemoveAndDestroyConstraint(cons.Body1, cons.Body2); | ||
75 | |||
76 | m_constraints.Add(cons); | ||
77 | } | ||
78 | |||
79 | return true; | ||
80 | } | ||
81 | |||
82 | // Get the constraint between two bodies. There can be only one. | ||
83 | // Return 'true' if a constraint was found. | ||
84 | public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint) | ||
85 | { | ||
86 | bool found = false; | ||
87 | BSConstraint foundConstraint = null; | ||
88 | |||
89 | uint lookingID1 = body1.ID; | ||
90 | uint lookingID2 = body2.ID; | ||
91 | lock (m_constraints) | ||
92 | { | ||
93 | foreach (BSConstraint constrain in m_constraints) | ||
94 | { | ||
95 | if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2) | ||
96 | || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1)) | ||
97 | { | ||
98 | foundConstraint = constrain; | ||
99 | found = true; | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | returnConstraint = foundConstraint; | ||
105 | return found; | ||
106 | } | ||
107 | |||
108 | // Remove any constraint between the passed bodies. | ||
109 | // Presumed there is only one such constraint possible. | ||
110 | // Return 'true' if a constraint was found and destroyed. | ||
111 | public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2) | ||
112 | { | ||
113 | bool ret = false; | ||
114 | lock (m_constraints) | ||
115 | { | ||
116 | BSConstraint constrain; | ||
117 | if (this.TryGetConstraint(body1, body2, out constrain)) | ||
118 | { | ||
119 | // remove the constraint from our collection | ||
120 | ret = RemoveAndDestroyConstraint(constrain); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | // The constraint MUST exist in the collection | ||
128 | // Could be called if the constraint was previously removed. | ||
129 | // Return 'true' if the constraint was actually removed and disposed. | ||
130 | public bool RemoveAndDestroyConstraint(BSConstraint constrain) | ||
131 | { | ||
132 | bool removed = false; | ||
133 | lock (m_constraints) | ||
134 | { | ||
135 | // remove the constraint from our collection | ||
136 | removed = m_constraints.Remove(constrain); | ||
137 | } | ||
138 | // Dispose() is safe to call multiple times | ||
139 | constrain.Dispose(); | ||
140 | return removed; | ||
141 | } | ||
142 | |||
143 | // Remove all constraints that reference the passed body. | ||
144 | // Return 'true' if any constraints were destroyed. | ||
145 | public bool RemoveAndDestroyConstraint(BulletBody body1) | ||
146 | { | ||
147 | List<BSConstraint> toRemove = new List<BSConstraint>(); | ||
148 | uint lookingID = body1.ID; | ||
149 | lock (m_constraints) | ||
150 | { | ||
151 | foreach (BSConstraint constrain in m_constraints) | ||
152 | { | ||
153 | if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) | ||
154 | { | ||
155 | toRemove.Add(constrain); | ||
156 | } | ||
157 | } | ||
158 | foreach (BSConstraint constrain in toRemove) | ||
159 | { | ||
160 | m_constraints.Remove(constrain); | ||
161 | constrain.Dispose(); | ||
162 | } | ||
163 | } | ||
164 | return (toRemove.Count > 0); | ||
165 | } | ||
166 | |||
167 | public bool RecalculateAllConstraints() | ||
168 | { | ||
169 | bool ret = false; | ||
170 | lock (m_constraints) | ||
171 | { | ||
172 | foreach (BSConstraint constrain in m_constraints) | ||
173 | { | ||
174 | constrain.CalculateTransforms(); | ||
175 | ret = true; | ||
176 | } | ||
177 | } | ||
178 | return ret; | ||
179 | } | ||
180 | } | ||
181 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs new file mode 100755 index 0000000..7a76a9a --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs | |||
@@ -0,0 +1,54 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | |||
35 | public sealed class BSConstraintConeTwist : BSConstraint | ||
36 | { | ||
37 | public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } } | ||
38 | |||
39 | public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
40 | Vector3 frameInAloc, Quaternion frameInArot, | ||
41 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
42 | bool disableCollisionsBetweenLinkedBodies) | ||
43 | : base(world) | ||
44 | { | ||
45 | m_body1 = obj1; | ||
46 | m_body2 = obj2; | ||
47 | m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2, | ||
48 | frameInAloc, frameInArot, frameInBloc, frameInBrot, | ||
49 | disableCollisionsBetweenLinkedBodies); | ||
50 | m_enabled = true; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs new file mode 100755 index 0000000..ed89f63 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs | |||
@@ -0,0 +1,55 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | |||
35 | public sealed class BSConstraintHinge : BSConstraint | ||
36 | { | ||
37 | public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } | ||
38 | |||
39 | public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
40 | Vector3 pivotInA, Vector3 pivotInB, | ||
41 | Vector3 axisInA, Vector3 axisInB, | ||
42 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
43 | : base(world) | ||
44 | { | ||
45 | m_body1 = obj1; | ||
46 | m_body2 = obj2; | ||
47 | m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, | ||
48 | pivotInA, pivotInB, axisInA, axisInB, | ||
49 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | ||
50 | m_enabled = true; | ||
51 | } | ||
52 | |||
53 | } | ||
54 | |||
55 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs new file mode 100755 index 0000000..37cfa07 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs | |||
@@ -0,0 +1,55 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | |||
35 | public sealed class BSConstraintSlider : BSConstraint | ||
36 | { | ||
37 | public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } } | ||
38 | |||
39 | public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
40 | Vector3 frameInAloc, Quaternion frameInArot, | ||
41 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
42 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
43 | : base(world) | ||
44 | { | ||
45 | m_body1 = obj1; | ||
46 | m_body2 = obj2; | ||
47 | m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2, | ||
48 | frameInAloc, frameInArot, frameInBloc, frameInBrot, | ||
49 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | ||
50 | m_enabled = true; | ||
51 | } | ||
52 | |||
53 | } | ||
54 | |||
55 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs new file mode 100755 index 0000000..8e7ddff --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs | |||
@@ -0,0 +1,103 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | |||
35 | public sealed class BSConstraintSpring : BSConstraint6Dof | ||
36 | { | ||
37 | public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } } | ||
38 | |||
39 | public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
40 | Vector3 frame1Loc, Quaternion frame1Rot, | ||
41 | Vector3 frame2Loc, Quaternion frame2Rot, | ||
42 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
43 | :base(world, obj1, obj2) | ||
44 | { | ||
45 | m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2, | ||
46 | frame1Loc, frame1Rot, frame2Loc, frame2Rot, | ||
47 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | ||
48 | m_enabled = true; | ||
49 | |||
50 | PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
51 | obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); | ||
52 | PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", | ||
53 | m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | ||
54 | } | ||
55 | |||
56 | public bool SetAxisEnable(int pIndex, bool pAxisEnable) | ||
57 | { | ||
58 | PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}", | ||
59 | m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable); | ||
60 | PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable)); | ||
61 | return true; | ||
62 | } | ||
63 | |||
64 | public bool SetStiffness(int pIndex, float pStiffness) | ||
65 | { | ||
66 | PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}", | ||
67 | m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness); | ||
68 | PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness); | ||
69 | return true; | ||
70 | } | ||
71 | |||
72 | public bool SetDamping(int pIndex, float pDamping) | ||
73 | { | ||
74 | PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}", | ||
75 | m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping); | ||
76 | PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping); | ||
77 | return true; | ||
78 | } | ||
79 | |||
80 | public bool SetEquilibriumPoint(int pIndex, float pEqPoint) | ||
81 | { | ||
82 | PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}", | ||
83 | m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint); | ||
84 | PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint); | ||
85 | return true; | ||
86 | } | ||
87 | |||
88 | public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq) | ||
89 | { | ||
90 | PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}", | ||
91 | m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq); | ||
92 | PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X); | ||
93 | PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y); | ||
94 | PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z); | ||
95 | PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X); | ||
96 | PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y); | ||
97 | PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z); | ||
98 | return true; | ||
99 | } | ||
100 | |||
101 | } | ||
102 | |||
103 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs new file mode 100644 index 0000000..c6d6331 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs | |||
@@ -0,0 +1,1800 @@ | |||
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 | * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial | ||
28 | * are Copyright (c) 2009 Linden Research, Inc and are used under their license | ||
29 | * of Creative Commons Attribution-Share Alike 3.0 | ||
30 | * (http://creativecommons.org/licenses/by-sa/3.0/). | ||
31 | */ | ||
32 | |||
33 | using System; | ||
34 | using System.Collections.Generic; | ||
35 | using System.Reflection; | ||
36 | using System.Runtime.InteropServices; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Physics.Manager; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
42 | { | ||
43 | public sealed class BSDynamics : BSActor | ||
44 | { | ||
45 | #pragma warning disable 414 | ||
46 | private static string LogHeader = "[BULLETSIM VEHICLE]"; | ||
47 | #pragma warning restore 414 | ||
48 | |||
49 | // the prim this dynamic controller belongs to | ||
50 | private BSPrimLinkable ControllingPrim { get; set; } | ||
51 | |||
52 | private bool m_haveRegisteredForSceneEvents; | ||
53 | |||
54 | // mass of the vehicle fetched each time we're calles | ||
55 | private float m_vehicleMass; | ||
56 | |||
57 | // Vehicle properties | ||
58 | public Vehicle Type { get; set; } | ||
59 | |||
60 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier | ||
61 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: | ||
62 | // HOVER_TERRAIN_ONLY | ||
63 | // HOVER_GLOBAL_HEIGHT | ||
64 | // NO_DEFLECTION_UP | ||
65 | // HOVER_WATER_ONLY | ||
66 | // HOVER_UP_ONLY | ||
67 | // LIMIT_MOTOR_UP | ||
68 | // LIMIT_ROLL_ONLY | ||
69 | private Vector3 m_BlockingEndPoint = Vector3.Zero; | ||
70 | private Quaternion m_RollreferenceFrame = Quaternion.Identity; | ||
71 | private Quaternion m_referenceFrame = Quaternion.Identity; | ||
72 | |||
73 | // Linear properties | ||
74 | private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); | ||
75 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | ||
76 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center | ||
77 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | ||
78 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | ||
79 | private float m_linearMotorDecayTimescale = 1; | ||
80 | private float m_linearMotorTimescale = 1; | ||
81 | private Vector3 m_lastLinearVelocityVector = Vector3.Zero; | ||
82 | private Vector3 m_lastPositionVector = Vector3.Zero; | ||
83 | // private bool m_LinearMotorSetLastFrame = false; | ||
84 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | ||
85 | |||
86 | //Angular properties | ||
87 | private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); | ||
88 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | ||
89 | // private int m_angularMotorApply = 0; // application frame counter | ||
90 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | ||
91 | private float m_angularMotorTimescale = 1; // motor angular velocity ramp up rate | ||
92 | private float m_angularMotorDecayTimescale = 1; // motor angular velocity decay rate | ||
93 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | ||
94 | private Vector3 m_lastAngularVelocity = Vector3.Zero; | ||
95 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | ||
96 | |||
97 | //Deflection properties | ||
98 | private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection"); | ||
99 | private float m_angularDeflectionEfficiency = 0; | ||
100 | private float m_angularDeflectionTimescale = 0; | ||
101 | private float m_linearDeflectionEfficiency = 0; | ||
102 | private float m_linearDeflectionTimescale = 0; | ||
103 | |||
104 | //Banking properties | ||
105 | private float m_bankingEfficiency = 0; | ||
106 | private float m_bankingMix = 1; | ||
107 | private float m_bankingTimescale = 0; | ||
108 | |||
109 | //Hover and Buoyancy properties | ||
110 | private BSVMotor m_hoverMotor = new BSVMotor("Hover"); | ||
111 | private float m_VhoverHeight = 0f; | ||
112 | private float m_VhoverEfficiency = 0f; | ||
113 | private float m_VhoverTimescale = 0f; | ||
114 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | ||
115 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | ||
116 | private float m_VehicleBuoyancy = 0f; | ||
117 | private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set | ||
118 | |||
119 | //Attractor properties | ||
120 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); | ||
121 | private float m_verticalAttractionEfficiency = 1.0f; // damped | ||
122 | private float m_verticalAttractionCutoff = 500f; // per the documentation | ||
123 | // Timescale > cutoff means no vert attractor. | ||
124 | private float m_verticalAttractionTimescale = 510f; | ||
125 | |||
126 | // Just some recomputed constants: | ||
127 | #pragma warning disable 414 | ||
128 | static readonly float TwoPI = ((float)Math.PI) * 2f; | ||
129 | static readonly float FourPI = ((float)Math.PI) * 4f; | ||
130 | static readonly float PIOverFour = ((float)Math.PI) / 4f; | ||
131 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; | ||
132 | #pragma warning restore 414 | ||
133 | |||
134 | public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) | ||
135 | : base(myScene, myPrim, actorName) | ||
136 | { | ||
137 | Type = Vehicle.TYPE_NONE; | ||
138 | m_haveRegisteredForSceneEvents = false; | ||
139 | |||
140 | ControllingPrim = myPrim as BSPrimLinkable; | ||
141 | if (ControllingPrim == null) | ||
142 | { | ||
143 | // THIS CANNOT HAPPEN!! | ||
144 | } | ||
145 | VDetailLog("{0},Creation", ControllingPrim.LocalID); | ||
146 | } | ||
147 | |||
148 | // Return 'true' if this vehicle is doing vehicle things | ||
149 | public bool IsActive | ||
150 | { | ||
151 | get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); } | ||
152 | } | ||
153 | |||
154 | // Return 'true' if this a vehicle that should be sitting on the ground | ||
155 | public bool IsGroundVehicle | ||
156 | { | ||
157 | get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); } | ||
158 | } | ||
159 | |||
160 | #region Vehicle parameter setting | ||
161 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
162 | { | ||
163 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); | ||
164 | float clampTemp; | ||
165 | |||
166 | switch (pParam) | ||
167 | { | ||
168 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | ||
169 | m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f); | ||
170 | break; | ||
171 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | ||
172 | m_angularDeflectionTimescale = ClampInRange(0.25f, pValue, 120); | ||
173 | break; | ||
174 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | ||
175 | m_angularMotorDecayTimescale = ClampInRange(0.25f, pValue, 120); | ||
176 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | ||
177 | break; | ||
178 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | ||
179 | m_angularMotorTimescale = ClampInRange(0.25f, pValue, 120); | ||
180 | m_angularMotor.TimeScale = m_angularMotorTimescale; | ||
181 | break; | ||
182 | case Vehicle.BANKING_EFFICIENCY: | ||
183 | m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); | ||
184 | break; | ||
185 | case Vehicle.BANKING_MIX: | ||
186 | m_bankingMix = ClampInRange(0.01f, pValue, 1); | ||
187 | break; | ||
188 | case Vehicle.BANKING_TIMESCALE: | ||
189 | m_bankingTimescale = ClampInRange(0.25f, pValue, 120); | ||
190 | break; | ||
191 | case Vehicle.BUOYANCY: | ||
192 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); | ||
193 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); | ||
194 | break; | ||
195 | case Vehicle.HOVER_EFFICIENCY: | ||
196 | m_VhoverEfficiency = ClampInRange(0.01f, pValue, 1f); | ||
197 | break; | ||
198 | case Vehicle.HOVER_HEIGHT: | ||
199 | m_VhoverHeight = ClampInRange(0f, pValue, 1000000f); | ||
200 | break; | ||
201 | case Vehicle.HOVER_TIMESCALE: | ||
202 | m_VhoverTimescale = ClampInRange(0.01f, pValue, 120); | ||
203 | break; | ||
204 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | ||
205 | m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f); | ||
206 | break; | ||
207 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | ||
208 | m_linearDeflectionTimescale = ClampInRange(0.01f, pValue, 120); | ||
209 | break; | ||
210 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | ||
211 | m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); | ||
212 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | ||
213 | break; | ||
214 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | ||
215 | m_linearMotorTimescale = ClampInRange(0.01f, pValue, 120); | ||
216 | m_linearMotor.TimeScale = m_linearMotorTimescale; | ||
217 | break; | ||
218 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | ||
219 | m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); | ||
220 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | ||
221 | break; | ||
222 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | ||
223 | m_verticalAttractionTimescale = ClampInRange(0.01f, pValue, 120); | ||
224 | m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; | ||
225 | break; | ||
226 | |||
227 | // These are vector properties but the engine lets you use a single float value to | ||
228 | // set all of the components to the same value | ||
229 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
230 | clampTemp = ClampInRange(0.01f, pValue, 120); | ||
231 | m_angularFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp); | ||
232 | break; | ||
233 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
234 | clampTemp = ClampInRange(-TwoPI, pValue, TwoPI); | ||
235 | m_angularMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp); | ||
236 | m_angularMotor.Zero(); | ||
237 | m_angularMotor.SetTarget(m_angularMotorDirection); | ||
238 | break; | ||
239 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
240 | clampTemp = ClampInRange(0.01f, pValue, 120); | ||
241 | m_linearFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp); | ||
242 | break; | ||
243 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
244 | clampTemp = ClampInRange(-BSParam.MaxLinearVelocity, pValue, BSParam.MaxLinearVelocity); | ||
245 | m_linearMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp); | ||
246 | m_linearMotorDirectionLASTSET = new Vector3(clampTemp, clampTemp, clampTemp); | ||
247 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
248 | break; | ||
249 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
250 | clampTemp = ClampInRange(-1000, pValue, 1000); | ||
251 | m_linearMotorOffset = new Vector3(clampTemp, clampTemp, clampTemp); | ||
252 | break; | ||
253 | |||
254 | } | ||
255 | }//end ProcessFloatVehicleParam | ||
256 | |||
257 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | ||
258 | { | ||
259 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); | ||
260 | switch (pParam) | ||
261 | { | ||
262 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
263 | pValue.X = ClampInRange(0.25f, pValue.X, 120); | ||
264 | pValue.Y = ClampInRange(0.25f, pValue.Y, 120); | ||
265 | pValue.Z = ClampInRange(0.25f, pValue.Z, 120); | ||
266 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
267 | break; | ||
268 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
269 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | ||
270 | pValue.X = ClampInRange(-FourPI, pValue.X, FourPI); | ||
271 | pValue.Y = ClampInRange(-FourPI, pValue.Y, FourPI); | ||
272 | pValue.Z = ClampInRange(-FourPI, pValue.Z, FourPI); | ||
273 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
274 | m_angularMotor.Zero(); | ||
275 | m_angularMotor.SetTarget(m_angularMotorDirection); | ||
276 | break; | ||
277 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
278 | pValue.X = ClampInRange(0.25f, pValue.X, 120); | ||
279 | pValue.Y = ClampInRange(0.25f, pValue.Y, 120); | ||
280 | pValue.Z = ClampInRange(0.25f, pValue.Z, 120); | ||
281 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
282 | break; | ||
283 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
284 | pValue.X = ClampInRange(-BSParam.MaxLinearVelocity, pValue.X, BSParam.MaxLinearVelocity); | ||
285 | pValue.Y = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Y, BSParam.MaxLinearVelocity); | ||
286 | pValue.Z = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Z, BSParam.MaxLinearVelocity); | ||
287 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
288 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
289 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
290 | break; | ||
291 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
292 | // Not sure the correct range to limit this variable | ||
293 | pValue.X = ClampInRange(-1000, pValue.X, 1000); | ||
294 | pValue.Y = ClampInRange(-1000, pValue.Y, 1000); | ||
295 | pValue.Z = ClampInRange(-1000, pValue.Z, 1000); | ||
296 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
297 | break; | ||
298 | case Vehicle.BLOCK_EXIT: | ||
299 | // Not sure the correct range to limit this variable | ||
300 | pValue.X = ClampInRange(-10000, pValue.X, 10000); | ||
301 | pValue.Y = ClampInRange(-10000, pValue.Y, 10000); | ||
302 | pValue.Z = ClampInRange(-10000, pValue.Z, 10000); | ||
303 | m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
304 | break; | ||
305 | } | ||
306 | }//end ProcessVectorVehicleParam | ||
307 | |||
308 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | ||
309 | { | ||
310 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); | ||
311 | switch (pParam) | ||
312 | { | ||
313 | case Vehicle.REFERENCE_FRAME: | ||
314 | m_referenceFrame = pValue; | ||
315 | break; | ||
316 | case Vehicle.ROLL_FRAME: | ||
317 | m_RollreferenceFrame = pValue; | ||
318 | break; | ||
319 | } | ||
320 | }//end ProcessRotationVehicleParam | ||
321 | |||
322 | internal void ProcessVehicleFlags(int pParam, bool remove) | ||
323 | { | ||
324 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove); | ||
325 | VehicleFlag parm = (VehicleFlag)pParam; | ||
326 | if (pParam == -1) | ||
327 | m_flags = (VehicleFlag)0; | ||
328 | else | ||
329 | { | ||
330 | if (remove) | ||
331 | m_flags &= ~parm; | ||
332 | else | ||
333 | m_flags |= parm; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | public void ProcessTypeChange(Vehicle pType) | ||
338 | { | ||
339 | VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType); | ||
340 | // Set Defaults For Type | ||
341 | Type = pType; | ||
342 | switch (pType) | ||
343 | { | ||
344 | case Vehicle.TYPE_NONE: | ||
345 | m_linearMotorDirection = Vector3.Zero; | ||
346 | m_linearMotorTimescale = 0; | ||
347 | m_linearMotorDecayTimescale = 0; | ||
348 | m_linearFrictionTimescale = new Vector3(0, 0, 0); | ||
349 | |||
350 | m_angularMotorDirection = Vector3.Zero; | ||
351 | m_angularMotorDecayTimescale = 0; | ||
352 | m_angularMotorTimescale = 0; | ||
353 | m_angularFrictionTimescale = new Vector3(0, 0, 0); | ||
354 | |||
355 | m_VhoverHeight = 0; | ||
356 | m_VhoverEfficiency = 0; | ||
357 | m_VhoverTimescale = 0; | ||
358 | m_VehicleBuoyancy = 0; | ||
359 | |||
360 | m_linearDeflectionEfficiency = 1; | ||
361 | m_linearDeflectionTimescale = 1; | ||
362 | |||
363 | m_angularDeflectionEfficiency = 0; | ||
364 | m_angularDeflectionTimescale = 1000; | ||
365 | |||
366 | m_verticalAttractionEfficiency = 0; | ||
367 | m_verticalAttractionTimescale = 0; | ||
368 | |||
369 | m_bankingEfficiency = 0; | ||
370 | m_bankingTimescale = 1000; | ||
371 | m_bankingMix = 1; | ||
372 | |||
373 | m_referenceFrame = Quaternion.Identity; | ||
374 | m_flags = (VehicleFlag)0; | ||
375 | |||
376 | break; | ||
377 | |||
378 | case Vehicle.TYPE_SLED: | ||
379 | m_linearMotorDirection = Vector3.Zero; | ||
380 | m_linearMotorTimescale = 1000; | ||
381 | m_linearMotorDecayTimescale = 120; | ||
382 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
383 | |||
384 | m_angularMotorDirection = Vector3.Zero; | ||
385 | m_angularMotorTimescale = 1000; | ||
386 | m_angularMotorDecayTimescale = 120; | ||
387 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
388 | |||
389 | m_VhoverHeight = 0; | ||
390 | m_VhoverEfficiency = 10; // TODO: this looks wrong!! | ||
391 | m_VhoverTimescale = 10; | ||
392 | m_VehicleBuoyancy = 0; | ||
393 | |||
394 | m_linearDeflectionEfficiency = 1; | ||
395 | m_linearDeflectionTimescale = 1; | ||
396 | |||
397 | m_angularDeflectionEfficiency = 1; | ||
398 | m_angularDeflectionTimescale = 1000; | ||
399 | |||
400 | m_verticalAttractionEfficiency = 0; | ||
401 | m_verticalAttractionTimescale = 0; | ||
402 | |||
403 | m_bankingEfficiency = 0; | ||
404 | m_bankingTimescale = 10; | ||
405 | m_bankingMix = 1; | ||
406 | |||
407 | m_referenceFrame = Quaternion.Identity; | ||
408 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
409 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
410 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | ||
411 | | VehicleFlag.HOVER_UP_ONLY); | ||
412 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
413 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
414 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
415 | |||
416 | break; | ||
417 | case Vehicle.TYPE_CAR: | ||
418 | m_linearMotorDirection = Vector3.Zero; | ||
419 | m_linearMotorTimescale = 1; | ||
420 | m_linearMotorDecayTimescale = 60; | ||
421 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
422 | |||
423 | m_angularMotorDirection = Vector3.Zero; | ||
424 | m_angularMotorTimescale = 1; | ||
425 | m_angularMotorDecayTimescale = 0.8f; | ||
426 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
427 | |||
428 | m_VhoverHeight = 0; | ||
429 | m_VhoverEfficiency = 0; | ||
430 | m_VhoverTimescale = 1000; | ||
431 | m_VehicleBuoyancy = 0; | ||
432 | |||
433 | m_linearDeflectionEfficiency = 1; | ||
434 | m_linearDeflectionTimescale = 2; | ||
435 | |||
436 | m_angularDeflectionEfficiency = 0; | ||
437 | m_angularDeflectionTimescale = 10; | ||
438 | |||
439 | m_verticalAttractionEfficiency = 1f; | ||
440 | m_verticalAttractionTimescale = 10f; | ||
441 | |||
442 | m_bankingEfficiency = -0.2f; | ||
443 | m_bankingMix = 1; | ||
444 | m_bankingTimescale = 1; | ||
445 | |||
446 | m_referenceFrame = Quaternion.Identity; | ||
447 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
448 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
449 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
450 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
451 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
452 | | VehicleFlag.LIMIT_MOTOR_UP | ||
453 | | VehicleFlag.HOVER_UP_ONLY); | ||
454 | break; | ||
455 | case Vehicle.TYPE_BOAT: | ||
456 | m_linearMotorDirection = Vector3.Zero; | ||
457 | m_linearMotorTimescale = 5; | ||
458 | m_linearMotorDecayTimescale = 60; | ||
459 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
460 | |||
461 | m_angularMotorDirection = Vector3.Zero; | ||
462 | m_angularMotorTimescale = 4; | ||
463 | m_angularMotorDecayTimescale = 4; | ||
464 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
465 | |||
466 | m_VhoverHeight = 0; | ||
467 | m_VhoverEfficiency = 0.5f; | ||
468 | m_VhoverTimescale = 2; | ||
469 | m_VehicleBuoyancy = 1; | ||
470 | |||
471 | m_linearDeflectionEfficiency = 0.5f; | ||
472 | m_linearDeflectionTimescale = 3; | ||
473 | |||
474 | m_angularDeflectionEfficiency = 0.5f; | ||
475 | m_angularDeflectionTimescale = 5; | ||
476 | |||
477 | m_verticalAttractionEfficiency = 0.5f; | ||
478 | m_verticalAttractionTimescale = 5f; | ||
479 | |||
480 | m_bankingEfficiency = -0.3f; | ||
481 | m_bankingMix = 0.8f; | ||
482 | m_bankingTimescale = 1; | ||
483 | |||
484 | m_referenceFrame = Quaternion.Identity; | ||
485 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | ||
486 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | ||
487 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
488 | | VehicleFlag.HOVER_UP_ONLY); | ||
489 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
490 | | VehicleFlag.LIMIT_MOTOR_UP | ||
491 | | VehicleFlag.HOVER_WATER_ONLY); | ||
492 | break; | ||
493 | case Vehicle.TYPE_AIRPLANE: | ||
494 | m_linearMotorDirection = Vector3.Zero; | ||
495 | m_linearMotorTimescale = 2; | ||
496 | m_linearMotorDecayTimescale = 60; | ||
497 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
498 | |||
499 | m_angularMotorDirection = Vector3.Zero; | ||
500 | m_angularMotorTimescale = 4; | ||
501 | m_angularMotorDecayTimescale = 4; | ||
502 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
503 | |||
504 | m_VhoverHeight = 0; | ||
505 | m_VhoverEfficiency = 0.5f; | ||
506 | m_VhoverTimescale = 1000; | ||
507 | m_VehicleBuoyancy = 0; | ||
508 | |||
509 | m_linearDeflectionEfficiency = 0.5f; | ||
510 | m_linearDeflectionTimescale = 3; | ||
511 | |||
512 | m_angularDeflectionEfficiency = 1; | ||
513 | m_angularDeflectionTimescale = 2; | ||
514 | |||
515 | m_verticalAttractionEfficiency = 0.9f; | ||
516 | m_verticalAttractionTimescale = 2f; | ||
517 | |||
518 | m_bankingEfficiency = 1; | ||
519 | m_bankingMix = 0.7f; | ||
520 | m_bankingTimescale = 2; | ||
521 | |||
522 | m_referenceFrame = Quaternion.Identity; | ||
523 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
524 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
525 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | ||
526 | | VehicleFlag.HOVER_UP_ONLY | ||
527 | | VehicleFlag.NO_DEFLECTION_UP | ||
528 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
529 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
530 | break; | ||
531 | case Vehicle.TYPE_BALLOON: | ||
532 | m_linearMotorDirection = Vector3.Zero; | ||
533 | m_linearMotorTimescale = 5; | ||
534 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
535 | m_linearMotorDecayTimescale = 60; | ||
536 | |||
537 | m_angularMotorDirection = Vector3.Zero; | ||
538 | m_angularMotorTimescale = 6; | ||
539 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
540 | m_angularMotorDecayTimescale = 10; | ||
541 | |||
542 | m_VhoverHeight = 5; | ||
543 | m_VhoverEfficiency = 0.8f; | ||
544 | m_VhoverTimescale = 10; | ||
545 | m_VehicleBuoyancy = 1; | ||
546 | |||
547 | m_linearDeflectionEfficiency = 0; | ||
548 | m_linearDeflectionTimescale = 5; | ||
549 | |||
550 | m_angularDeflectionEfficiency = 0; | ||
551 | m_angularDeflectionTimescale = 5; | ||
552 | |||
553 | m_verticalAttractionEfficiency = 1f; | ||
554 | m_verticalAttractionTimescale = 100f; | ||
555 | |||
556 | m_bankingEfficiency = 0; | ||
557 | m_bankingMix = 0.7f; | ||
558 | m_bankingTimescale = 5; | ||
559 | |||
560 | m_referenceFrame = Quaternion.Identity; | ||
561 | |||
562 | m_referenceFrame = Quaternion.Identity; | ||
563 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
564 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
565 | | VehicleFlag.HOVER_UP_ONLY | ||
566 | | VehicleFlag.NO_DEFLECTION_UP | ||
567 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
568 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | ||
569 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
570 | break; | ||
571 | } | ||
572 | |||
573 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f); | ||
574 | // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
575 | |||
576 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f); | ||
577 | // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
578 | |||
579 | /* Not implemented | ||
580 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | ||
581 | BSMotor.Infinite, BSMotor.InfiniteVector, | ||
582 | m_verticalAttractionEfficiency); | ||
583 | // Z goes away and we keep X and Y | ||
584 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
585 | */ | ||
586 | |||
587 | if (this.Type == Vehicle.TYPE_NONE) | ||
588 | { | ||
589 | UnregisterForSceneEvents(); | ||
590 | } | ||
591 | else | ||
592 | { | ||
593 | RegisterForSceneEvents(); | ||
594 | } | ||
595 | |||
596 | // Update any physical parameters based on this type. | ||
597 | Refresh(); | ||
598 | } | ||
599 | #endregion // Vehicle parameter setting | ||
600 | |||
601 | // BSActor.Refresh() | ||
602 | public override void Refresh() | ||
603 | { | ||
604 | // If asking for a refresh, reset the physical parameters before the next simulation step. | ||
605 | // Called whether active or not since the active state may be updated before the next step. | ||
606 | m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate() | ||
607 | { | ||
608 | SetPhysicalParameters(); | ||
609 | }); | ||
610 | } | ||
611 | |||
612 | // Some of the properties of this prim may have changed. | ||
613 | // Do any updating needed for a vehicle | ||
614 | private void SetPhysicalParameters() | ||
615 | { | ||
616 | if (IsActive) | ||
617 | { | ||
618 | // Remember the mass so we don't have to fetch it every step | ||
619 | m_vehicleMass = ControllingPrim.TotalMass; | ||
620 | |||
621 | // Friction affects are handled by this vehicle code | ||
622 | // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); | ||
623 | // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); | ||
624 | ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); | ||
625 | ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); | ||
626 | |||
627 | // Moderate angular movement introduced by Bullet. | ||
628 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | ||
629 | // Maybe compute linear and angular factor and damping from params. | ||
630 | m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping); | ||
631 | m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor); | ||
632 | m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); | ||
633 | |||
634 | // Vehicles report collision events so we know when it's on the ground | ||
635 | // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
636 | ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
637 | |||
638 | // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); | ||
639 | // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; | ||
640 | // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); | ||
641 | // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); | ||
642 | ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass); | ||
643 | |||
644 | // Set the gravity for the vehicle depending on the buoyancy | ||
645 | // TODO: what should be done if prim and vehicle buoyancy differ? | ||
646 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); | ||
647 | // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. | ||
648 | // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); | ||
649 | ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); | ||
650 | |||
651 | VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", | ||
652 | ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, | ||
653 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, | ||
654 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor | ||
655 | ); | ||
656 | } | ||
657 | else | ||
658 | { | ||
659 | if (ControllingPrim.PhysBody.HasPhysicalBody) | ||
660 | m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
661 | // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | // BSActor.RemoveBodyDependencies | ||
666 | public override void RemoveDependencies() | ||
667 | { | ||
668 | Refresh(); | ||
669 | } | ||
670 | |||
671 | // BSActor.Release() | ||
672 | public override void Dispose() | ||
673 | { | ||
674 | VDetailLog("{0},Dispose", ControllingPrim.LocalID); | ||
675 | UnregisterForSceneEvents(); | ||
676 | Type = Vehicle.TYPE_NONE; | ||
677 | Enabled = false; | ||
678 | return; | ||
679 | } | ||
680 | |||
681 | private void RegisterForSceneEvents() | ||
682 | { | ||
683 | if (!m_haveRegisteredForSceneEvents) | ||
684 | { | ||
685 | m_physicsScene.BeforeStep += this.Step; | ||
686 | m_physicsScene.AfterStep += this.PostStep; | ||
687 | ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty; | ||
688 | m_haveRegisteredForSceneEvents = true; | ||
689 | } | ||
690 | } | ||
691 | |||
692 | private void UnregisterForSceneEvents() | ||
693 | { | ||
694 | if (m_haveRegisteredForSceneEvents) | ||
695 | { | ||
696 | m_physicsScene.BeforeStep -= this.Step; | ||
697 | m_physicsScene.AfterStep -= this.PostStep; | ||
698 | ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty; | ||
699 | m_haveRegisteredForSceneEvents = false; | ||
700 | } | ||
701 | } | ||
702 | |||
703 | private void PreUpdateProperty(ref EntityProperties entprop) | ||
704 | { | ||
705 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet | ||
706 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
707 | if (IsActive) | ||
708 | { | ||
709 | entprop.RotationalVelocity = Vector3.Zero; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | #region Known vehicle value functions | ||
714 | // Vehicle physical parameters that we buffer from constant getting and setting. | ||
715 | // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set. | ||
716 | // Changing is remembered and the parameter is stored back into the physics engine only if updated. | ||
717 | // This does two things: 1) saves continuious calls into unmanaged code, and | ||
718 | // 2) signals when a physics property update must happen back to the simulator | ||
719 | // to update values modified for the vehicle. | ||
720 | private int m_knownChanged; | ||
721 | private int m_knownHas; | ||
722 | private float m_knownTerrainHeight; | ||
723 | private float m_knownWaterLevel; | ||
724 | private Vector3 m_knownPosition; | ||
725 | private Vector3 m_knownVelocity; | ||
726 | private Vector3 m_knownForce; | ||
727 | private Vector3 m_knownForceImpulse; | ||
728 | private Quaternion m_knownOrientation; | ||
729 | private Vector3 m_knownRotationalVelocity; | ||
730 | private Vector3 m_knownRotationalForce; | ||
731 | private Vector3 m_knownRotationalImpulse; | ||
732 | |||
733 | private const int m_knownChangedPosition = 1 << 0; | ||
734 | private const int m_knownChangedVelocity = 1 << 1; | ||
735 | private const int m_knownChangedForce = 1 << 2; | ||
736 | private const int m_knownChangedForceImpulse = 1 << 3; | ||
737 | private const int m_knownChangedOrientation = 1 << 4; | ||
738 | private const int m_knownChangedRotationalVelocity = 1 << 5; | ||
739 | private const int m_knownChangedRotationalForce = 1 << 6; | ||
740 | private const int m_knownChangedRotationalImpulse = 1 << 7; | ||
741 | private const int m_knownChangedTerrainHeight = 1 << 8; | ||
742 | private const int m_knownChangedWaterLevel = 1 << 9; | ||
743 | |||
744 | public void ForgetKnownVehicleProperties() | ||
745 | { | ||
746 | m_knownHas = 0; | ||
747 | m_knownChanged = 0; | ||
748 | } | ||
749 | // Push all the changed values back into the physics engine | ||
750 | public void PushKnownChanged() | ||
751 | { | ||
752 | if (m_knownChanged != 0) | ||
753 | { | ||
754 | if ((m_knownChanged & m_knownChangedPosition) != 0) | ||
755 | ControllingPrim.ForcePosition = m_knownPosition; | ||
756 | |||
757 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | ||
758 | ControllingPrim.ForceOrientation = m_knownOrientation; | ||
759 | |||
760 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | ||
761 | { | ||
762 | ControllingPrim.ForceVelocity = m_knownVelocity; | ||
763 | // Fake out Bullet by making it think the velocity is the same as last time. | ||
764 | // Bullet does a bunch of smoothing for changing parameters. | ||
765 | // Since the vehicle is demanding this setting, we override Bullet's smoothing | ||
766 | // by telling Bullet the value was the same last time. | ||
767 | // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity); | ||
768 | } | ||
769 | |||
770 | if ((m_knownChanged & m_knownChangedForce) != 0) | ||
771 | ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); | ||
772 | |||
773 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) | ||
774 | ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); | ||
775 | |||
776 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | ||
777 | { | ||
778 | ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity; | ||
779 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); | ||
780 | } | ||
781 | |||
782 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) | ||
783 | ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); | ||
784 | |||
785 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | ||
786 | { | ||
787 | ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); | ||
788 | } | ||
789 | |||
790 | // If we set one of the values (ie, the physics engine didn't do it) we must force | ||
791 | // an UpdateProperties event to send the changes up to the simulator. | ||
792 | m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody); | ||
793 | } | ||
794 | m_knownChanged = 0; | ||
795 | } | ||
796 | |||
797 | // Since the computation of terrain height can be a little involved, this routine | ||
798 | // is used to fetch the height only once for each vehicle simulation step. | ||
799 | Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1); | ||
800 | private float GetTerrainHeight(Vector3 pos) | ||
801 | { | ||
802 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) | ||
803 | { | ||
804 | lastRememberedHeightPos = pos; | ||
805 | m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
806 | m_knownHas |= m_knownChangedTerrainHeight; | ||
807 | } | ||
808 | return m_knownTerrainHeight; | ||
809 | } | ||
810 | |||
811 | // Since the computation of water level can be a little involved, this routine | ||
812 | // is used ot fetch the level only once for each vehicle simulation step. | ||
813 | Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1); | ||
814 | private float GetWaterLevel(Vector3 pos) | ||
815 | { | ||
816 | if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos) | ||
817 | { | ||
818 | lastRememberedWaterHeightPos = pos; | ||
819 | m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
820 | m_knownHas |= m_knownChangedWaterLevel; | ||
821 | } | ||
822 | return m_knownWaterLevel; | ||
823 | } | ||
824 | |||
825 | private Vector3 VehiclePosition | ||
826 | { | ||
827 | get | ||
828 | { | ||
829 | if ((m_knownHas & m_knownChangedPosition) == 0) | ||
830 | { | ||
831 | m_knownPosition = ControllingPrim.ForcePosition; | ||
832 | m_knownHas |= m_knownChangedPosition; | ||
833 | } | ||
834 | return m_knownPosition; | ||
835 | } | ||
836 | set | ||
837 | { | ||
838 | m_knownPosition = value; | ||
839 | m_knownChanged |= m_knownChangedPosition; | ||
840 | m_knownHas |= m_knownChangedPosition; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | private Quaternion VehicleOrientation | ||
845 | { | ||
846 | get | ||
847 | { | ||
848 | if ((m_knownHas & m_knownChangedOrientation) == 0) | ||
849 | { | ||
850 | m_knownOrientation = ControllingPrim.ForceOrientation; | ||
851 | m_knownHas |= m_knownChangedOrientation; | ||
852 | } | ||
853 | return m_knownOrientation; | ||
854 | } | ||
855 | set | ||
856 | { | ||
857 | m_knownOrientation = value; | ||
858 | m_knownChanged |= m_knownChangedOrientation; | ||
859 | m_knownHas |= m_knownChangedOrientation; | ||
860 | } | ||
861 | } | ||
862 | |||
863 | private Vector3 VehicleVelocity | ||
864 | { | ||
865 | get | ||
866 | { | ||
867 | if ((m_knownHas & m_knownChangedVelocity) == 0) | ||
868 | { | ||
869 | m_knownVelocity = ControllingPrim.ForceVelocity; | ||
870 | m_knownHas |= m_knownChangedVelocity; | ||
871 | } | ||
872 | return m_knownVelocity; | ||
873 | } | ||
874 | set | ||
875 | { | ||
876 | m_knownVelocity = value; | ||
877 | m_knownChanged |= m_knownChangedVelocity; | ||
878 | m_knownHas |= m_knownChangedVelocity; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | private void VehicleAddForce(Vector3 pForce) | ||
883 | { | ||
884 | if ((m_knownHas & m_knownChangedForce) == 0) | ||
885 | { | ||
886 | m_knownForce = Vector3.Zero; | ||
887 | m_knownHas |= m_knownChangedForce; | ||
888 | } | ||
889 | m_knownForce += pForce; | ||
890 | m_knownChanged |= m_knownChangedForce; | ||
891 | } | ||
892 | |||
893 | private void VehicleAddForceImpulse(Vector3 pImpulse) | ||
894 | { | ||
895 | if ((m_knownHas & m_knownChangedForceImpulse) == 0) | ||
896 | { | ||
897 | m_knownForceImpulse = Vector3.Zero; | ||
898 | m_knownHas |= m_knownChangedForceImpulse; | ||
899 | } | ||
900 | m_knownForceImpulse += pImpulse; | ||
901 | m_knownChanged |= m_knownChangedForceImpulse; | ||
902 | } | ||
903 | |||
904 | private Vector3 VehicleRotationalVelocity | ||
905 | { | ||
906 | get | ||
907 | { | ||
908 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) | ||
909 | { | ||
910 | m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity; | ||
911 | m_knownHas |= m_knownChangedRotationalVelocity; | ||
912 | } | ||
913 | return (Vector3)m_knownRotationalVelocity; | ||
914 | } | ||
915 | set | ||
916 | { | ||
917 | m_knownRotationalVelocity = value; | ||
918 | m_knownChanged |= m_knownChangedRotationalVelocity; | ||
919 | m_knownHas |= m_knownChangedRotationalVelocity; | ||
920 | } | ||
921 | } | ||
922 | private void VehicleAddAngularForce(Vector3 aForce) | ||
923 | { | ||
924 | if ((m_knownHas & m_knownChangedRotationalForce) == 0) | ||
925 | { | ||
926 | m_knownRotationalForce = Vector3.Zero; | ||
927 | } | ||
928 | m_knownRotationalForce += aForce; | ||
929 | m_knownChanged |= m_knownChangedRotationalForce; | ||
930 | m_knownHas |= m_knownChangedRotationalForce; | ||
931 | } | ||
932 | private void VehicleAddRotationalImpulse(Vector3 pImpulse) | ||
933 | { | ||
934 | if ((m_knownHas & m_knownChangedRotationalImpulse) == 0) | ||
935 | { | ||
936 | m_knownRotationalImpulse = Vector3.Zero; | ||
937 | m_knownHas |= m_knownChangedRotationalImpulse; | ||
938 | } | ||
939 | m_knownRotationalImpulse += pImpulse; | ||
940 | m_knownChanged |= m_knownChangedRotationalImpulse; | ||
941 | } | ||
942 | |||
943 | // Vehicle relative forward velocity | ||
944 | private Vector3 VehicleForwardVelocity | ||
945 | { | ||
946 | get | ||
947 | { | ||
948 | return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleFrameOrientation)); | ||
949 | } | ||
950 | } | ||
951 | |||
952 | private float VehicleForwardSpeed | ||
953 | { | ||
954 | get | ||
955 | { | ||
956 | return VehicleForwardVelocity.X; | ||
957 | } | ||
958 | } | ||
959 | private Quaternion VehicleFrameOrientation | ||
960 | { | ||
961 | get | ||
962 | { | ||
963 | return VehicleOrientation * m_referenceFrame; | ||
964 | } | ||
965 | } | ||
966 | |||
967 | #endregion // Known vehicle value functions | ||
968 | |||
969 | // One step of the vehicle properties for the next 'pTimestep' seconds. | ||
970 | internal void Step(float pTimestep) | ||
971 | { | ||
972 | if (!IsActive) return; | ||
973 | |||
974 | ForgetKnownVehicleProperties(); | ||
975 | |||
976 | MoveLinear(pTimestep); | ||
977 | MoveAngular(pTimestep); | ||
978 | |||
979 | LimitRotation(pTimestep); | ||
980 | |||
981 | // remember the position so next step we can limit absolute movement effects | ||
982 | m_lastPositionVector = VehiclePosition; | ||
983 | |||
984 | // If we forced the changing of some vehicle parameters, update the values and | ||
985 | // for the physics engine to note the changes so an UpdateProperties event will happen. | ||
986 | PushKnownChanged(); | ||
987 | |||
988 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) | ||
989 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); | ||
990 | |||
991 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", | ||
992 | ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); | ||
993 | } | ||
994 | |||
995 | // Called after the simulation step | ||
996 | internal void PostStep(float pTimestep) | ||
997 | { | ||
998 | if (!IsActive) return; | ||
999 | |||
1000 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) | ||
1001 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); | ||
1002 | } | ||
1003 | |||
1004 | // Apply the effect of the linear motor and other linear motions (like hover and float). | ||
1005 | private void MoveLinear(float pTimestep) | ||
1006 | { | ||
1007 | ComputeLinearVelocity(pTimestep); | ||
1008 | |||
1009 | ComputeLinearDeflection(pTimestep); | ||
1010 | |||
1011 | ComputeLinearTerrainHeightCorrection(pTimestep); | ||
1012 | |||
1013 | ComputeLinearHover(pTimestep); | ||
1014 | |||
1015 | ComputeLinearBlockingEndPoint(pTimestep); | ||
1016 | |||
1017 | ComputeLinearMotorUp(pTimestep); | ||
1018 | |||
1019 | ApplyGravity(pTimestep); | ||
1020 | |||
1021 | // If not changing some axis, reduce out velocity | ||
1022 | if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0) | ||
1023 | { | ||
1024 | Vector3 vel = VehicleVelocity; | ||
1025 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
1026 | { | ||
1027 | vel.X = 0; | ||
1028 | } | ||
1029 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
1030 | { | ||
1031 | vel.Y = 0; | ||
1032 | } | ||
1033 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
1034 | { | ||
1035 | vel.Z = 0; | ||
1036 | } | ||
1037 | VehicleVelocity = vel; | ||
1038 | } | ||
1039 | |||
1040 | // ================================================================== | ||
1041 | // Clamp high or low velocities | ||
1042 | float newVelocityLengthSq = VehicleVelocity.LengthSquared(); | ||
1043 | if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared) | ||
1044 | { | ||
1045 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG | ||
1046 | VehicleVelocity /= VehicleVelocity.Length(); | ||
1047 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; | ||
1048 | VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", | ||
1049 | ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); | ||
1050 | } | ||
1051 | else if (newVelocityLengthSq < BSParam.VehicleMinLinearVelocitySquared) | ||
1052 | { | ||
1053 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG | ||
1054 | VDetailLog("{0}, MoveLinear,clampMin,origVelW={1},lenSq={2}", | ||
1055 | ControllingPrim.LocalID, origVelW, newVelocityLengthSq); | ||
1056 | VehicleVelocity = Vector3.Zero; | ||
1057 | } | ||
1058 | |||
1059 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity ); | ||
1060 | |||
1061 | } // end MoveLinear() | ||
1062 | |||
1063 | public void ComputeLinearVelocity(float pTimestep) | ||
1064 | { | ||
1065 | // Step the motor from the current value. Get the correction needed this step. | ||
1066 | Vector3 origVelW = VehicleVelocity; // DEBUG | ||
1067 | Vector3 currentVelV = VehicleForwardVelocity; | ||
1068 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); | ||
1069 | |||
1070 | // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction. | ||
1071 | Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); | ||
1072 | linearMotorCorrectionV -= (currentVelV * frictionFactorV); | ||
1073 | |||
1074 | // Motor is vehicle coordinates. Rotate it to world coordinates | ||
1075 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleFrameOrientation; | ||
1076 | |||
1077 | // If we're a ground vehicle, don't add any upward Z movement | ||
1078 | if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0) | ||
1079 | { | ||
1080 | if (linearMotorVelocityW.Z > 0f) | ||
1081 | linearMotorVelocityW.Z = 0f; | ||
1082 | } | ||
1083 | |||
1084 | // Add this correction to the velocity to make it faster/slower. | ||
1085 | VehicleVelocity += linearMotorVelocityW; | ||
1086 | |||
1087 | VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}", | ||
1088 | ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV, | ||
1089 | linearMotorVelocityW, VehicleVelocity, frictionFactorV); | ||
1090 | } | ||
1091 | |||
1092 | //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis | ||
1093 | //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity | ||
1094 | private void ComputeLinearDeflection(float pTimestep) | ||
1095 | { | ||
1096 | Vector3 linearDeflectionV = Vector3.Zero; | ||
1097 | Vector3 velocityV = VehicleForwardVelocity; | ||
1098 | |||
1099 | if (BSParam.VehicleEnableLinearDeflection) | ||
1100 | { | ||
1101 | // Velocity in Y and Z dimensions is movement to the side or turning. | ||
1102 | // Compute deflection factor from the to the side and rotational velocity | ||
1103 | linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y); | ||
1104 | linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z); | ||
1105 | |||
1106 | // Velocity to the side and around is corrected and moved into the forward direction | ||
1107 | linearDeflectionV.X += Math.Abs(linearDeflectionV.Y); | ||
1108 | linearDeflectionV.X += Math.Abs(linearDeflectionV.Z); | ||
1109 | |||
1110 | // Scale the deflection to the fractional simulation time | ||
1111 | linearDeflectionV *= pTimestep; | ||
1112 | |||
1113 | // Subtract the sideways and rotational velocity deflection factors while adding the correction forward | ||
1114 | linearDeflectionV *= new Vector3(1, -1, -1); | ||
1115 | |||
1116 | // Correction is vehicle relative. Convert to world coordinates. | ||
1117 | Vector3 linearDeflectionW = linearDeflectionV * VehicleFrameOrientation; | ||
1118 | |||
1119 | // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall. | ||
1120 | if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision) | ||
1121 | { | ||
1122 | linearDeflectionW.Z = 0f; | ||
1123 | } | ||
1124 | |||
1125 | VehicleVelocity += linearDeflectionW; | ||
1126 | |||
1127 | VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}", | ||
1128 | ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV); | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) | ||
1133 | { | ||
1134 | // If below the terrain, move us above the ground a little. | ||
1135 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. | ||
1136 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) | ||
1137 | { | ||
1138 | // Force position because applying force won't get the vehicle through the terrain | ||
1139 | Vector3 newPosition = VehiclePosition; | ||
1140 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; | ||
1141 | VehiclePosition = newPosition; | ||
1142 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | ||
1143 | ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | ||
1144 | } | ||
1145 | } | ||
1146 | |||
1147 | public void ComputeLinearHover(float pTimestep) | ||
1148 | { | ||
1149 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | ||
1150 | // m_VhoverTimescale: time to achieve height | ||
1151 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0 && (m_VhoverHeight > 0) && (m_VhoverTimescale < 300)) | ||
1152 | { | ||
1153 | // We should hover, get the target height | ||
1154 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | ||
1155 | { | ||
1156 | m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; | ||
1157 | } | ||
1158 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | ||
1159 | { | ||
1160 | m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; | ||
1161 | } | ||
1162 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | ||
1163 | { | ||
1164 | m_VhoverTargetHeight = m_VhoverHeight; | ||
1165 | } | ||
1166 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | ||
1167 | { | ||
1168 | // If body is already heigher, use its height as target height | ||
1169 | if (VehiclePosition.Z > m_VhoverTargetHeight) | ||
1170 | { | ||
1171 | m_VhoverTargetHeight = VehiclePosition.Z; | ||
1172 | |||
1173 | // A 'misfeature' of this flag is that if the vehicle is above it's hover height, | ||
1174 | // the vehicle's buoyancy goes away. This is an SL bug that got used by so many | ||
1175 | // scripts that it could not be changed. | ||
1176 | // So, if above the height, reapply gravity if buoyancy had it turned off. | ||
1177 | if (m_VehicleBuoyancy != 0) | ||
1178 | { | ||
1179 | Vector3 appliedGravity = ControllingPrim.ComputeGravity(ControllingPrim.Buoyancy) * m_vehicleMass; | ||
1180 | VehicleAddForce(appliedGravity); | ||
1181 | } | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | ||
1186 | { | ||
1187 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) | ||
1188 | { | ||
1189 | Vector3 pos = VehiclePosition; | ||
1190 | pos.Z = m_VhoverTargetHeight; | ||
1191 | VehiclePosition = pos; | ||
1192 | |||
1193 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos); | ||
1194 | } | ||
1195 | } | ||
1196 | else | ||
1197 | { | ||
1198 | // Error is positive if below the target and negative if above. | ||
1199 | Vector3 hpos = VehiclePosition; | ||
1200 | float verticalError = m_VhoverTargetHeight - hpos.Z; | ||
1201 | float verticalCorrection = verticalError / m_VhoverTimescale; | ||
1202 | verticalCorrection *= m_VhoverEfficiency; | ||
1203 | |||
1204 | hpos.Z += verticalCorrection; | ||
1205 | VehiclePosition = hpos; | ||
1206 | |||
1207 | // Since we are hovering, we need to do the opposite of falling -- get rid of world Z | ||
1208 | Vector3 vel = VehicleVelocity; | ||
1209 | vel.Z = 0f; | ||
1210 | VehicleVelocity = vel; | ||
1211 | |||
1212 | /* | ||
1213 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; | ||
1214 | Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity); | ||
1215 | verticalCorrection *= m_vehicleMass; | ||
1216 | |||
1217 | // TODO: implement m_VhoverEfficiency correctly | ||
1218 | VehicleAddForceImpulse(verticalCorrection); | ||
1219 | */ | ||
1220 | |||
1221 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", | ||
1222 | ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency, | ||
1223 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, | ||
1224 | verticalError, verticalCorrection); | ||
1225 | } | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | public bool ComputeLinearBlockingEndPoint(float pTimestep) | ||
1230 | { | ||
1231 | bool changed = false; | ||
1232 | |||
1233 | Vector3 pos = VehiclePosition; | ||
1234 | Vector3 posChange = pos - m_lastPositionVector; | ||
1235 | if (m_BlockingEndPoint != Vector3.Zero) | ||
1236 | { | ||
1237 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | ||
1238 | { | ||
1239 | pos.X -= posChange.X + 1; | ||
1240 | changed = true; | ||
1241 | } | ||
1242 | if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) | ||
1243 | { | ||
1244 | pos.Y -= posChange.Y + 1; | ||
1245 | changed = true; | ||
1246 | } | ||
1247 | if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) | ||
1248 | { | ||
1249 | pos.Z -= posChange.Z + 1; | ||
1250 | changed = true; | ||
1251 | } | ||
1252 | if (pos.X <= 0) | ||
1253 | { | ||
1254 | pos.X += posChange.X + 1; | ||
1255 | changed = true; | ||
1256 | } | ||
1257 | if (pos.Y <= 0) | ||
1258 | { | ||
1259 | pos.Y += posChange.Y + 1; | ||
1260 | changed = true; | ||
1261 | } | ||
1262 | if (changed) | ||
1263 | { | ||
1264 | VehiclePosition = pos; | ||
1265 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | ||
1266 | ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos); | ||
1267 | } | ||
1268 | } | ||
1269 | return changed; | ||
1270 | } | ||
1271 | |||
1272 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | ||
1273 | // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when | ||
1274 | // used with conjunction with banking: the strength of the banking will decay when the | ||
1275 | // vehicle no longer experiences collisions. The decay timescale is the same as | ||
1276 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | ||
1277 | // when they are in mid jump. | ||
1278 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | ||
1279 | // This is just using the ground and a general collision check. Should really be using | ||
1280 | // a downward raycast to find what is below. | ||
1281 | public void ComputeLinearMotorUp(float pTimestep) | ||
1282 | { | ||
1283 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | ||
1284 | { | ||
1285 | // This code tries to decide if the object is not on the ground and then pushing down | ||
1286 | /* | ||
1287 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); | ||
1288 | distanceAboveGround = VehiclePosition.Z - targetHeight; | ||
1289 | // Not colliding if the vehicle is off the ground | ||
1290 | if (!Prim.HasSomeCollision) | ||
1291 | { | ||
1292 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | ||
1293 | VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); | ||
1294 | } | ||
1295 | // TODO: this calculation is wrong. From the description at | ||
1296 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | ||
1297 | // has a decay factor. This says this force should | ||
1298 | // be computed with a motor. | ||
1299 | // TODO: add interaction with banking. | ||
1300 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", | ||
1301 | Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret); | ||
1302 | */ | ||
1303 | |||
1304 | // Another approach is to measure if we're going up. If going up and not colliding, | ||
1305 | // the vehicle is in the air. Fix that by pushing down. | ||
1306 | if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1) | ||
1307 | { | ||
1308 | // Get rid of any of the velocity vector that is pushing us up. | ||
1309 | float upVelocity = VehicleVelocity.Z; | ||
1310 | VehicleVelocity += new Vector3(0, 0, -upVelocity); | ||
1311 | |||
1312 | /* | ||
1313 | // If we're pointed up into the air, we should nose down | ||
1314 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | ||
1315 | // The rotation around the Y axis is pitch up or down | ||
1316 | if (pointingDirection.Y > 0.01f) | ||
1317 | { | ||
1318 | float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y); | ||
1319 | Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f); | ||
1320 | // Rotate into world coordinates and apply to vehicle | ||
1321 | angularCorrectionVector *= VehicleOrientation; | ||
1322 | VehicleAddAngularForce(angularCorrectionVector); | ||
1323 | VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}", | ||
1324 | Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector); | ||
1325 | } | ||
1326 | */ | ||
1327 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", | ||
1328 | ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity); | ||
1329 | } | ||
1330 | } | ||
1331 | } | ||
1332 | |||
1333 | private void ApplyGravity(float pTimeStep) | ||
1334 | { | ||
1335 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; | ||
1336 | |||
1337 | // Hack to reduce downward force if the vehicle is probably sitting on the ground | ||
1338 | if (ControllingPrim.HasSomeCollision && IsGroundVehicle) | ||
1339 | appliedGravity *= BSParam.VehicleGroundGravityFudge; | ||
1340 | |||
1341 | VehicleAddForce(appliedGravity); | ||
1342 | |||
1343 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}", | ||
1344 | ControllingPrim.LocalID, m_VehicleGravity, | ||
1345 | ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); | ||
1346 | } | ||
1347 | |||
1348 | // ======================================================================= | ||
1349 | // ======================================================================= | ||
1350 | // Apply the effect of the angular motor. | ||
1351 | // The 'contribution' is how much angular correction velocity each function wants. | ||
1352 | // All the contributions are added together and the resulting velocity is | ||
1353 | // set directly on the vehicle. | ||
1354 | private void MoveAngular(float pTimestep) | ||
1355 | { | ||
1356 | ComputeAngularTurning(pTimestep); | ||
1357 | |||
1358 | ComputeAngularVerticalAttraction(); | ||
1359 | |||
1360 | ComputeAngularDeflection(); | ||
1361 | |||
1362 | ComputeAngularBanking(); | ||
1363 | |||
1364 | // ================================================================== | ||
1365 | if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f)) | ||
1366 | { | ||
1367 | // The vehicle is not adding anything angular wise. | ||
1368 | VehicleRotationalVelocity = Vector3.Zero; | ||
1369 | VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID); | ||
1370 | } | ||
1371 | else | ||
1372 | { | ||
1373 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity); | ||
1374 | } | ||
1375 | |||
1376 | // ================================================================== | ||
1377 | //Offset section | ||
1378 | if (m_linearMotorOffset != Vector3.Zero) | ||
1379 | { | ||
1380 | //Offset of linear velocity doesn't change the linear velocity, | ||
1381 | // but causes a torque to be applied, for example... | ||
1382 | // | ||
1383 | // IIIII >>> IIIII | ||
1384 | // IIIII >>> IIIII | ||
1385 | // IIIII >>> IIIII | ||
1386 | // ^ | ||
1387 | // | Applying a force at the arrow will cause the object to move forward, but also rotate | ||
1388 | // | ||
1389 | // | ||
1390 | // The torque created is the linear velocity crossed with the offset | ||
1391 | |||
1392 | // TODO: this computation should be in the linear section | ||
1393 | // because that is where we know the impulse being applied. | ||
1394 | Vector3 torqueFromOffset = Vector3.Zero; | ||
1395 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); | ||
1396 | if (float.IsNaN(torqueFromOffset.X)) | ||
1397 | torqueFromOffset.X = 0; | ||
1398 | if (float.IsNaN(torqueFromOffset.Y)) | ||
1399 | torqueFromOffset.Y = 0; | ||
1400 | if (float.IsNaN(torqueFromOffset.Z)) | ||
1401 | torqueFromOffset.Z = 0; | ||
1402 | |||
1403 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); | ||
1404 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset); | ||
1405 | } | ||
1406 | |||
1407 | } | ||
1408 | |||
1409 | private void ComputeAngularTurning(float pTimestep) | ||
1410 | { | ||
1411 | // The user wants this many radians per second angular change? | ||
1412 | Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG | ||
1413 | Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleFrameOrientation); | ||
1414 | Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); | ||
1415 | |||
1416 | // ================================================================== | ||
1417 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | ||
1418 | // This flag prevents linear deflection parallel to world z-axis. This is useful | ||
1419 | // for preventing ground vehicles with large linear deflection, like bumper cars, | ||
1420 | // from climbing their linear deflection into the sky. | ||
1421 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | ||
1422 | // TODO: This is here because this is where ODE put it but documentation says it | ||
1423 | // is a linear effect. Where should this check go? | ||
1424 | //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
1425 | // { | ||
1426 | // angularMotorContributionV.X = 0f; | ||
1427 | // angularMotorContributionV.Y = 0f; | ||
1428 | // } | ||
1429 | |||
1430 | // Reduce any velocity by friction. | ||
1431 | Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); | ||
1432 | angularMotorContributionV -= (currentAngularV * frictionFactorW); | ||
1433 | |||
1434 | Vector3 angularMotorContributionW = angularMotorContributionV * VehicleFrameOrientation; | ||
1435 | VehicleRotationalVelocity += angularMotorContributionW; | ||
1436 | |||
1437 | VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}", | ||
1438 | ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW); | ||
1439 | } | ||
1440 | |||
1441 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1442 | // Some vehicles, like boats, should always keep their up-side up. This can be done by | ||
1443 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to | ||
1444 | // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the | ||
1445 | // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, | ||
1446 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An | ||
1447 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an | ||
1448 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. | ||
1449 | public void ComputeAngularVerticalAttraction() | ||
1450 | { | ||
1451 | |||
1452 | // If vertical attaction timescale is reasonable | ||
1453 | if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1454 | { | ||
1455 | Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleFrameOrientation; | ||
1456 | switch (BSParam.VehicleAngularVerticalAttractionAlgorithm) | ||
1457 | { | ||
1458 | case 0: | ||
1459 | { | ||
1460 | //Another formula to try got from : | ||
1461 | //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html | ||
1462 | |||
1463 | // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 | ||
1464 | // since only computing half the distance between the angles. | ||
1465 | float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; | ||
1466 | |||
1467 | // Make a prediction of where the up axis will be when this is applied rather then where it is now as | ||
1468 | // this makes for a smoother adjustment and less fighting between the various forces. | ||
1469 | Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); | ||
1470 | |||
1471 | // This is only half the distance to the target so it will take 2 seconds to complete the turn. | ||
1472 | Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); | ||
1473 | |||
1474 | if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != 0) | ||
1475 | { | ||
1476 | Vector3 vehicleForwardAxis = Vector3.UnitX * VehicleFrameOrientation; | ||
1477 | torqueVector = ProjectVector(torqueVector, vehicleForwardAxis); | ||
1478 | } | ||
1479 | |||
1480 | // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared | ||
1481 | Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed; | ||
1482 | |||
1483 | VehicleRotationalVelocity += vertContributionV; | ||
1484 | |||
1485 | VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}", | ||
1486 | ControllingPrim.LocalID, | ||
1487 | verticalAttractionSpeed, | ||
1488 | vehicleUpAxis, | ||
1489 | predictedUp, | ||
1490 | torqueVector, | ||
1491 | vertContributionV); | ||
1492 | break; | ||
1493 | } | ||
1494 | case 1: | ||
1495 | { | ||
1496 | // Possible solution derived from a discussion at: | ||
1497 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no | ||
1498 | |||
1499 | // Create a rotation that is only the vehicle's rotation around Z | ||
1500 | Vector3 currentEulerW = Vector3.Zero; | ||
1501 | VehicleFrameOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z); | ||
1502 | Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z); | ||
1503 | |||
1504 | // Create the axis that is perpendicular to the up vector and the rotated up vector. | ||
1505 | Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleFrameOrientation); | ||
1506 | // Compute the angle between those to vectors. | ||
1507 | double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation))); | ||
1508 | // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical | ||
1509 | |||
1510 | // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. | ||
1511 | // TODO: add 'efficiency'. | ||
1512 | // differenceAngle /= m_verticalAttractionTimescale; | ||
1513 | |||
1514 | // Create the quaterian representing the correction angle | ||
1515 | Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle); | ||
1516 | |||
1517 | // Turn that quaternion into Euler values to make it into velocities to apply. | ||
1518 | Vector3 vertContributionW = Vector3.Zero; | ||
1519 | correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z); | ||
1520 | vertContributionW *= -1f; | ||
1521 | vertContributionW /= m_verticalAttractionTimescale; | ||
1522 | |||
1523 | VehicleRotationalVelocity += vertContributionW; | ||
1524 | |||
1525 | VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}", | ||
1526 | ControllingPrim.LocalID, | ||
1527 | vehicleUpAxis, | ||
1528 | differenceAxisW, | ||
1529 | differenceAngle, | ||
1530 | correctionRotationW, | ||
1531 | vertContributionW); | ||
1532 | break; | ||
1533 | } | ||
1534 | case 2: | ||
1535 | { | ||
1536 | Vector3 vertContributionV = Vector3.Zero; | ||
1537 | Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG | ||
1538 | |||
1539 | // Take a vector pointing up and convert it from world to vehicle relative coords. | ||
1540 | Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation); | ||
1541 | |||
1542 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1543 | // is now: | ||
1544 | // leaning to one side: rotated around the X axis with the Y value going | ||
1545 | // from zero (nearly straight up) to one (completely to the side)) or | ||
1546 | // leaning front-to-back: rotated around the Y axis with the value of X being between | ||
1547 | // zero and one. | ||
1548 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1549 | |||
1550 | // Y error means needed rotation around X axis and visa versa. | ||
1551 | // Since the error goes from zero to one, the asin is the corresponding angle. | ||
1552 | vertContributionV.X = (float)Math.Asin(verticalError.Y); | ||
1553 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) | ||
1554 | vertContributionV.Y = -(float)Math.Asin(verticalError.X); | ||
1555 | |||
1556 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1557 | if (verticalError.Z < 0f) | ||
1558 | { | ||
1559 | vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; | ||
1560 | // vertContribution.Y -= PIOverFour; | ||
1561 | } | ||
1562 | |||
1563 | // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. | ||
1564 | // Correction happens over a number of seconds. | ||
1565 | Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG | ||
1566 | |||
1567 | // The correction happens over the user's time period | ||
1568 | vertContributionV /= m_verticalAttractionTimescale; | ||
1569 | |||
1570 | // Rotate the vehicle rotation to the world coordinates. | ||
1571 | VehicleRotationalVelocity += (vertContributionV * VehicleFrameOrientation); | ||
1572 | |||
1573 | VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}", | ||
1574 | ControllingPrim.LocalID, | ||
1575 | vehicleUpAxis, | ||
1576 | origRotVelW, | ||
1577 | verticalError, | ||
1578 | unscaledContribVerticalErrorV, | ||
1579 | m_verticalAttractionEfficiency, | ||
1580 | m_verticalAttractionTimescale, | ||
1581 | vertContributionV); | ||
1582 | break; | ||
1583 | } | ||
1584 | default: | ||
1585 | { | ||
1586 | break; | ||
1587 | } | ||
1588 | } | ||
1589 | } | ||
1590 | } | ||
1591 | |||
1592 | // Angular correction to correct the direction the vehicle is pointing to be | ||
1593 | // the direction is should want to be pointing. | ||
1594 | // The vehicle is moving in some direction and correct its orientation to it is pointing | ||
1595 | // in that direction. | ||
1596 | // TODO: implement reference frame. | ||
1597 | public void ComputeAngularDeflection() | ||
1598 | { | ||
1599 | |||
1600 | if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) | ||
1601 | { | ||
1602 | Vector3 deflectContributionV = Vector3.Zero; | ||
1603 | |||
1604 | // The direction the vehicle is moving | ||
1605 | Vector3 movingDirection = VehicleVelocity; | ||
1606 | movingDirection.Normalize(); | ||
1607 | |||
1608 | // If the vehicle is going backward, it is still pointing forward | ||
1609 | movingDirection *= Math.Sign(VehicleForwardSpeed); | ||
1610 | |||
1611 | // The direction the vehicle is pointing | ||
1612 | Vector3 pointingDirection = Vector3.UnitX * VehicleFrameOrientation; | ||
1613 | //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep | ||
1614 | // from overshooting and allow this correction to merge with the Vertical Attraction peacefully. | ||
1615 | Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); | ||
1616 | predictedPointingDirection.Normalize(); | ||
1617 | |||
1618 | // The difference between what is and what should be. | ||
1619 | // Vector3 deflectionError = movingDirection - predictedPointingDirection; | ||
1620 | Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection); | ||
1621 | |||
1622 | // Don't try to correct very large errors (not our job) | ||
1623 | // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X); | ||
1624 | // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y); | ||
1625 | // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z); | ||
1626 | if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; | ||
1627 | if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; | ||
1628 | if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; | ||
1629 | |||
1630 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); | ||
1631 | |||
1632 | // Scale the correction by recovery timescale and efficiency | ||
1633 | // Not modeling a spring so clamp the scale to no more then the arc | ||
1634 | deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f); | ||
1635 | //deflectContributionV /= m_angularDeflectionTimescale; | ||
1636 | |||
1637 | VehicleRotationalVelocity += deflectContributionV; | ||
1638 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | ||
1639 | ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); | ||
1640 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}", | ||
1641 | ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection); | ||
1642 | } | ||
1643 | } | ||
1644 | |||
1645 | // Angular change to rotate the vehicle around the Z axis when the vehicle | ||
1646 | // is tipped around the X axis. | ||
1647 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1648 | // The vertical attractor feature must be enabled in order for the banking behavior to | ||
1649 | // function. The way banking works is this: a rotation around the vehicle's roll-axis will | ||
1650 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | ||
1651 | // of the yaw effect will be proportional to the | ||
1652 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | ||
1653 | // velocity along its preferred axis of motion. | ||
1654 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | ||
1655 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | ||
1656 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | ||
1657 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | ||
1658 | // Negating the banking coefficient will make it so that the vehicle leans to the | ||
1659 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | ||
1660 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | ||
1661 | // banking vehicles do what you want rather than what the laws of physics allow. | ||
1662 | // For example, consider a real motorcycle...it must be moving forward in order for | ||
1663 | // it to turn while banking, however video-game motorcycles are often configured | ||
1664 | // to turn in place when at a dead stop--because they are often easier to control | ||
1665 | // that way using the limited interface of the keyboard or game controller. The | ||
1666 | // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic | ||
1667 | // banking by functioning as a slider between a banking that is correspondingly | ||
1668 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | ||
1669 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | ||
1670 | // to "dynamic" where the banking is also proportional to its velocity along its | ||
1671 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | ||
1672 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | ||
1673 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | ||
1674 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | ||
1675 | // make a sluggish vehicle by giving it a timescale of several seconds. | ||
1676 | public void ComputeAngularBanking() | ||
1677 | { | ||
1678 | if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1679 | { | ||
1680 | Vector3 bankingContributionV = Vector3.Zero; | ||
1681 | |||
1682 | // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented. | ||
1683 | // As the vehicle rolls to the right or left, the Y value will increase from | ||
1684 | // zero (straight up) to 1 or -1 (full tilt right or left) | ||
1685 | Vector3 rollComponents = Vector3.UnitZ * VehicleFrameOrientation; | ||
1686 | |||
1687 | // Figure out the yaw value for this much roll. | ||
1688 | float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency; | ||
1689 | // actual error = static turn error + dynamic turn error | ||
1690 | float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed); | ||
1691 | |||
1692 | // TODO: the banking effect should not go to infinity but what to limit it to? | ||
1693 | // And what should happen when this is being added to a user defined yaw that is already PI*4? | ||
1694 | mixedYawAngle = ClampInRange(-FourPI, mixedYawAngle, FourPI); | ||
1695 | |||
1696 | // Build the force vector to change rotation from what it is to what it should be | ||
1697 | bankingContributionV.Z = -mixedYawAngle; | ||
1698 | |||
1699 | // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4. | ||
1700 | bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge; | ||
1701 | |||
1702 | VehicleRotationalVelocity += bankingContributionV; | ||
1703 | |||
1704 | |||
1705 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", | ||
1706 | ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | // This is from previous instantiations of XXXDynamics.cs. | ||
1711 | // Applies roll reference frame. | ||
1712 | // TODO: is this the right way to separate the code to do this operation? | ||
1713 | // Should this be in MoveAngular()? | ||
1714 | internal void LimitRotation(float timestep) | ||
1715 | { | ||
1716 | Quaternion rotq = VehicleOrientation; | ||
1717 | Quaternion m_rot = rotq; | ||
1718 | if (m_RollreferenceFrame != Quaternion.Identity) | ||
1719 | { | ||
1720 | if (rotq.X >= m_RollreferenceFrame.X) | ||
1721 | { | ||
1722 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); | ||
1723 | } | ||
1724 | if (rotq.Y >= m_RollreferenceFrame.Y) | ||
1725 | { | ||
1726 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); | ||
1727 | } | ||
1728 | if (rotq.X <= -m_RollreferenceFrame.X) | ||
1729 | { | ||
1730 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); | ||
1731 | } | ||
1732 | if (rotq.Y <= -m_RollreferenceFrame.Y) | ||
1733 | { | ||
1734 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); | ||
1735 | } | ||
1736 | } | ||
1737 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) | ||
1738 | { | ||
1739 | m_rot.X = 0; | ||
1740 | m_rot.Y = 0; | ||
1741 | } | ||
1742 | if (rotq != m_rot) | ||
1743 | { | ||
1744 | VehicleOrientation = m_rot; | ||
1745 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot); | ||
1746 | } | ||
1747 | |||
1748 | } | ||
1749 | |||
1750 | // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce | ||
1751 | // some value by to apply this friction. | ||
1752 | private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep) | ||
1753 | { | ||
1754 | Vector3 frictionFactor = Vector3.Zero; | ||
1755 | if (friction != BSMotor.InfiniteVector) | ||
1756 | { | ||
1757 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
1758 | // Individual friction components can be 'infinite' so compute each separately. | ||
1759 | frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X); | ||
1760 | frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y); | ||
1761 | frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z); | ||
1762 | frictionFactor *= pTimestep; | ||
1763 | } | ||
1764 | return frictionFactor; | ||
1765 | } | ||
1766 | |||
1767 | private float SortedClampInRange(float clampa, float val, float clampb) | ||
1768 | { | ||
1769 | if (clampa > clampb) | ||
1770 | { | ||
1771 | float temp = clampa; | ||
1772 | clampa = clampb; | ||
1773 | clampb = temp; | ||
1774 | } | ||
1775 | return ClampInRange(clampa, val, clampb); | ||
1776 | |||
1777 | } | ||
1778 | |||
1779 | //Given a Vector and a unit vector will return the amount of the vector is on the same axis as the unit. | ||
1780 | private Vector3 ProjectVector(Vector3 vector, Vector3 onNormal) | ||
1781 | { | ||
1782 | float vectorDot = Vector3.Dot(vector, onNormal); | ||
1783 | return onNormal * vectorDot; | ||
1784 | |||
1785 | } | ||
1786 | |||
1787 | private float ClampInRange(float low, float val, float high) | ||
1788 | { | ||
1789 | return Math.Max(low, Math.Min(val, high)); | ||
1790 | // return Utils.Clamp(val, low, high); | ||
1791 | } | ||
1792 | |||
1793 | // Invoke the detailed logger and output something if it's enabled. | ||
1794 | private void VDetailLog(string msg, params Object[] args) | ||
1795 | { | ||
1796 | if (ControllingPrim.PhysScene.VehicleLoggingEnabled) | ||
1797 | ControllingPrim.PhysScene.DetailLog(msg, args); | ||
1798 | } | ||
1799 | } | ||
1800 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs new file mode 100755 index 0000000..87eba33 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs | |||
@@ -0,0 +1,503 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | |||
36 | public abstract class BSLinkset | ||
37 | { | ||
38 | // private static string LogHeader = "[BULLETSIM LINKSET]"; | ||
39 | |||
40 | public enum LinksetImplementation | ||
41 | { | ||
42 | Constraint = 0, // linkset tied together with constraints | ||
43 | Compound = 1, // linkset tied together as a compound object | ||
44 | Manual = 2 // linkset tied together manually (code moves all the pieces) | ||
45 | } | ||
46 | // Create the correct type of linkset for this child | ||
47 | public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent) | ||
48 | { | ||
49 | BSLinkset ret = null; | ||
50 | |||
51 | switch (parent.LinksetType) | ||
52 | { | ||
53 | case LinksetImplementation.Constraint: | ||
54 | ret = new BSLinksetConstraints(physScene, parent); | ||
55 | break; | ||
56 | case LinksetImplementation.Compound: | ||
57 | ret = new BSLinksetCompound(physScene, parent); | ||
58 | break; | ||
59 | case LinksetImplementation.Manual: | ||
60 | // ret = new BSLinksetManual(physScene, parent); | ||
61 | break; | ||
62 | default: | ||
63 | ret = new BSLinksetCompound(physScene, parent); | ||
64 | break; | ||
65 | } | ||
66 | if (ret == null) | ||
67 | { | ||
68 | physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID); | ||
69 | } | ||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | public class BSLinkInfo | ||
74 | { | ||
75 | public BSPrimLinkable member; | ||
76 | public BSLinkInfo(BSPrimLinkable pMember) | ||
77 | { | ||
78 | member = pMember; | ||
79 | } | ||
80 | public virtual void ResetLink() { } | ||
81 | public virtual void SetLinkParameters(BSConstraint constrain) { } | ||
82 | // Returns 'true' if physical property updates from the child should be reported to the simulator | ||
83 | public virtual bool ShouldUpdateChildProperties() { return false; } | ||
84 | } | ||
85 | |||
86 | public LinksetImplementation LinksetImpl { get; protected set; } | ||
87 | |||
88 | public BSPrimLinkable LinksetRoot { get; protected set; } | ||
89 | |||
90 | protected BSScene m_physicsScene { get; private set; } | ||
91 | |||
92 | static int m_nextLinksetID = 1; | ||
93 | public int LinksetID { get; private set; } | ||
94 | |||
95 | // The children under the root in this linkset. | ||
96 | // protected HashSet<BSPrimLinkable> m_children; | ||
97 | protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children; | ||
98 | |||
99 | // We lock the diddling of linkset classes to prevent any badness. | ||
100 | // This locks the modification of the instances of this class. Changes | ||
101 | // to the physical representation is done via the tainting mechenism. | ||
102 | protected object m_linksetActivityLock = new Object(); | ||
103 | |||
104 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | ||
105 | public float LinksetMass { get; protected set; } | ||
106 | |||
107 | public virtual bool LinksetIsColliding { get { return false; } } | ||
108 | |||
109 | public OMV.Vector3 CenterOfMass | ||
110 | { | ||
111 | get { return ComputeLinksetCenterOfMass(); } | ||
112 | } | ||
113 | |||
114 | public OMV.Vector3 GeometricCenter | ||
115 | { | ||
116 | get { return ComputeLinksetGeometricCenter(); } | ||
117 | } | ||
118 | |||
119 | protected BSLinkset(BSScene scene, BSPrimLinkable parent) | ||
120 | { | ||
121 | // A simple linkset of one (no children) | ||
122 | LinksetID = m_nextLinksetID++; | ||
123 | // We create LOTS of linksets. | ||
124 | if (m_nextLinksetID <= 0) | ||
125 | m_nextLinksetID = 1; | ||
126 | m_physicsScene = scene; | ||
127 | LinksetRoot = parent; | ||
128 | m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>(); | ||
129 | LinksetMass = parent.RawMass; | ||
130 | Rebuilding = false; | ||
131 | RebuildScheduled = false; | ||
132 | |||
133 | parent.ClearDisplacement(); | ||
134 | } | ||
135 | |||
136 | // Link to a linkset where the child knows the parent. | ||
137 | // Parent changing should not happen so do some sanity checking. | ||
138 | // We return the parent's linkset so the child can track its membership. | ||
139 | // Called at runtime. | ||
140 | public BSLinkset AddMeToLinkset(BSPrimLinkable child) | ||
141 | { | ||
142 | lock (m_linksetActivityLock) | ||
143 | { | ||
144 | // Don't add the root to its own linkset | ||
145 | if (!IsRoot(child)) | ||
146 | AddChildToLinkset(child); | ||
147 | LinksetMass = ComputeLinksetMass(); | ||
148 | } | ||
149 | return this; | ||
150 | } | ||
151 | |||
152 | // Remove a child from a linkset. | ||
153 | // Returns a new linkset for the child which is a linkset of one (just the | ||
154 | // orphened child). | ||
155 | // Called at runtime. | ||
156 | public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime) | ||
157 | { | ||
158 | lock (m_linksetActivityLock) | ||
159 | { | ||
160 | if (IsRoot(child)) | ||
161 | { | ||
162 | // Cannot remove the root from a linkset. | ||
163 | return this; | ||
164 | } | ||
165 | RemoveChildFromLinkset(child, inTaintTime); | ||
166 | LinksetMass = ComputeLinksetMass(); | ||
167 | } | ||
168 | |||
169 | // The child is down to a linkset of just itself | ||
170 | return BSLinkset.Factory(m_physicsScene, child); | ||
171 | } | ||
172 | |||
173 | // Return 'true' if the passed object is the root object of this linkset | ||
174 | public bool IsRoot(BSPrimLinkable requestor) | ||
175 | { | ||
176 | return (requestor.LocalID == LinksetRoot.LocalID); | ||
177 | } | ||
178 | |||
179 | public int NumberOfChildren { get { return m_children.Count; } } | ||
180 | |||
181 | // Return 'true' if this linkset has any children (more than the root member) | ||
182 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | ||
183 | |||
184 | // Return 'true' if this child is in this linkset | ||
185 | public bool HasChild(BSPrimLinkable child) | ||
186 | { | ||
187 | bool ret = false; | ||
188 | lock (m_linksetActivityLock) | ||
189 | { | ||
190 | ret = m_children.ContainsKey(child); | ||
191 | } | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | // Perform an action on each member of the linkset including root prim. | ||
196 | // Depends on the action on whether this should be done at taint time. | ||
197 | public delegate bool ForEachMemberAction(BSPrimLinkable obj); | ||
198 | public virtual bool ForEachMember(ForEachMemberAction action) | ||
199 | { | ||
200 | bool ret = false; | ||
201 | lock (m_linksetActivityLock) | ||
202 | { | ||
203 | action(LinksetRoot); | ||
204 | foreach (BSPrimLinkable po in m_children.Keys) | ||
205 | { | ||
206 | if (action(po)) | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo) | ||
214 | { | ||
215 | bool ret = false; | ||
216 | BSLinkInfo found = null; | ||
217 | lock (m_linksetActivityLock) | ||
218 | { | ||
219 | ret = m_children.TryGetValue(child, out found); | ||
220 | } | ||
221 | foundInfo = found; | ||
222 | return ret; | ||
223 | } | ||
224 | // Perform an action on each member of the linkset including root prim. | ||
225 | // Depends on the action on whether this should be done at taint time. | ||
226 | public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); | ||
227 | public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action) | ||
228 | { | ||
229 | bool ret = false; | ||
230 | lock (m_linksetActivityLock) | ||
231 | { | ||
232 | foreach (BSLinkInfo po in m_children.Values) | ||
233 | { | ||
234 | if (action(po)) | ||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | // Check the type of the link and return 'true' if the link is flexible and the | ||
242 | // updates from the child should be sent to the simulator so things change. | ||
243 | public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child) | ||
244 | { | ||
245 | bool ret = false; | ||
246 | |||
247 | BSLinkInfo linkInfo; | ||
248 | if (m_children.TryGetValue(child, out linkInfo)) | ||
249 | { | ||
250 | ret = linkInfo.ShouldUpdateChildProperties(); | ||
251 | } | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | // Called after a simulation step to post a collision with this object. | ||
257 | // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have | ||
258 | // anything to add for the collision and it should be passed through normal processing. | ||
259 | // Default processing for a linkset. | ||
260 | public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee, | ||
261 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
262 | { | ||
263 | bool ret = false; | ||
264 | |||
265 | // prims in the same linkset cannot collide with each other | ||
266 | BSPrimLinkable convCollidee = collidee as BSPrimLinkable; | ||
267 | if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) | ||
268 | { | ||
269 | // By returning 'true', we tell the caller the collision has been 'handled' so it won't | ||
270 | // do anything about this collision and thus, effectivily, ignoring the collision. | ||
271 | ret = true; | ||
272 | } | ||
273 | else | ||
274 | { | ||
275 | // Not a collision between members of the linkset. Must be a real collision. | ||
276 | // So the linkset root can know if there is a collision anywhere in the linkset. | ||
277 | LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; | ||
278 | } | ||
279 | |||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | // I am the root of a linkset and a new child is being added | ||
284 | // Called while LinkActivity is locked. | ||
285 | protected abstract void AddChildToLinkset(BSPrimLinkable child); | ||
286 | |||
287 | // I am the root of a linkset and one of my children is being removed. | ||
288 | // Safe to call even if the child is not really in my linkset. | ||
289 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime); | ||
290 | |||
291 | // When physical properties are changed the linkset needs to recalculate | ||
292 | // its internal properties. | ||
293 | // May be called at runtime or taint-time. | ||
294 | public virtual void Refresh(BSPrimLinkable requestor) | ||
295 | { | ||
296 | LinksetMass = ComputeLinksetMass(); | ||
297 | } | ||
298 | |||
299 | // Flag denoting the linkset is in the process of being rebuilt. | ||
300 | // Used to know not the schedule a rebuild in the middle of a rebuild. | ||
301 | // Because of potential update calls that could want to schedule another rebuild. | ||
302 | protected bool Rebuilding { get; set; } | ||
303 | |||
304 | // Flag saying a linkset rebuild has been scheduled. | ||
305 | // This is turned on when the rebuild is requested and turned off when | ||
306 | // the rebuild is complete. Used to limit modifications to the | ||
307 | // linkset parameters while the linkset is in an intermediate state. | ||
308 | // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object | ||
309 | public bool RebuildScheduled { get; protected set; } | ||
310 | |||
311 | // The object is going dynamic (physical). Do any setup necessary | ||
312 | // for a dynamic linkset. | ||
313 | // Only the state of the passed object can be modified. The rest of the linkset | ||
314 | // has not yet been fully constructed. | ||
315 | // Return 'true' if any properties updated on the passed object. | ||
316 | // Called at taint-time! | ||
317 | public abstract bool MakeDynamic(BSPrimLinkable child); | ||
318 | |||
319 | public virtual bool AllPartsComplete | ||
320 | { | ||
321 | get { | ||
322 | bool ret = true; | ||
323 | this.ForEachMember((member) => | ||
324 | { | ||
325 | if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting) | ||
326 | { | ||
327 | ret = false; | ||
328 | return true; // exit loop | ||
329 | } | ||
330 | return false; // continue loop | ||
331 | }); | ||
332 | return ret; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | // The object is going static (non-physical). Do any setup necessary | ||
337 | // for a static linkset. | ||
338 | // Return 'true' if any properties updated on the passed object. | ||
339 | // Called at taint-time! | ||
340 | public abstract bool MakeStatic(BSPrimLinkable child); | ||
341 | |||
342 | // Called when a parameter update comes from the physics engine for any object | ||
343 | // of the linkset is received. | ||
344 | // Passed flag is update came from physics engine (true) or the user (false). | ||
345 | // Called at taint-time!! | ||
346 | public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject); | ||
347 | |||
348 | // Routine used when rebuilding the body of the root of the linkset | ||
349 | // Destroy all the constraints have have been made to root. | ||
350 | // This is called when the root body is changing. | ||
351 | // Returns 'true' of something was actually removed and would need restoring | ||
352 | // Called at taint-time!! | ||
353 | public abstract bool RemoveDependencies(BSPrimLinkable child); | ||
354 | |||
355 | // ================================================================ | ||
356 | // Some physical setting happen to all members of the linkset | ||
357 | public virtual void SetPhysicalFriction(float friction) | ||
358 | { | ||
359 | ForEachMember((member) => | ||
360 | { | ||
361 | if (member.PhysBody.HasPhysicalBody) | ||
362 | m_physicsScene.PE.SetFriction(member.PhysBody, friction); | ||
363 | return false; // 'false' says to continue looping | ||
364 | } | ||
365 | ); | ||
366 | } | ||
367 | public virtual void SetPhysicalRestitution(float restitution) | ||
368 | { | ||
369 | ForEachMember((member) => | ||
370 | { | ||
371 | if (member.PhysBody.HasPhysicalBody) | ||
372 | m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); | ||
373 | return false; // 'false' says to continue looping | ||
374 | } | ||
375 | ); | ||
376 | } | ||
377 | public virtual void SetPhysicalGravity(OMV.Vector3 gravity) | ||
378 | { | ||
379 | ForEachMember((member) => | ||
380 | { | ||
381 | if (member.PhysBody.HasPhysicalBody) | ||
382 | m_physicsScene.PE.SetGravity(member.PhysBody, gravity); | ||
383 | return false; // 'false' says to continue looping | ||
384 | } | ||
385 | ); | ||
386 | } | ||
387 | public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) | ||
388 | { | ||
389 | ForEachMember((member) => | ||
390 | { | ||
391 | if (member.PhysBody.HasPhysicalBody) | ||
392 | { | ||
393 | OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); | ||
394 | member.Inertia = inertia * inertiaFactor; | ||
395 | m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); | ||
396 | m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); | ||
397 | DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); | ||
398 | |||
399 | } | ||
400 | return false; // 'false' says to continue looping | ||
401 | } | ||
402 | ); | ||
403 | } | ||
404 | public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) | ||
405 | { | ||
406 | ForEachMember((member) => | ||
407 | { | ||
408 | if (member.PhysBody.HasPhysicalBody) | ||
409 | m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); | ||
410 | return false; // 'false' says to continue looping | ||
411 | } | ||
412 | ); | ||
413 | } | ||
414 | public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags) | ||
415 | { | ||
416 | ForEachMember((member) => | ||
417 | { | ||
418 | if (member.PhysBody.HasPhysicalBody) | ||
419 | m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags); | ||
420 | return false; // 'false' says to continue looping | ||
421 | } | ||
422 | ); | ||
423 | } | ||
424 | public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) | ||
425 | { | ||
426 | ForEachMember((member) => | ||
427 | { | ||
428 | if (member.PhysBody.HasPhysicalBody) | ||
429 | m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); | ||
430 | return false; // 'false' says to continue looping | ||
431 | } | ||
432 | ); | ||
433 | } | ||
434 | // ================================================================ | ||
435 | protected virtual float ComputeLinksetMass() | ||
436 | { | ||
437 | float mass = LinksetRoot.RawMass; | ||
438 | if (HasAnyChildren) | ||
439 | { | ||
440 | lock (m_linksetActivityLock) | ||
441 | { | ||
442 | foreach (BSPrimLinkable bp in m_children.Keys) | ||
443 | { | ||
444 | mass += bp.RawMass; | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | return mass; | ||
449 | } | ||
450 | |||
451 | // Computes linkset's center of mass in world coordinates. | ||
452 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() | ||
453 | { | ||
454 | OMV.Vector3 com; | ||
455 | lock (m_linksetActivityLock) | ||
456 | { | ||
457 | com = LinksetRoot.Position * LinksetRoot.RawMass; | ||
458 | float totalMass = LinksetRoot.RawMass; | ||
459 | |||
460 | foreach (BSPrimLinkable bp in m_children.Keys) | ||
461 | { | ||
462 | com += bp.Position * bp.RawMass; | ||
463 | totalMass += bp.RawMass; | ||
464 | } | ||
465 | if (totalMass != 0f) | ||
466 | com /= totalMass; | ||
467 | } | ||
468 | |||
469 | return com; | ||
470 | } | ||
471 | |||
472 | protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() | ||
473 | { | ||
474 | OMV.Vector3 com; | ||
475 | lock (m_linksetActivityLock) | ||
476 | { | ||
477 | com = LinksetRoot.Position; | ||
478 | |||
479 | foreach (BSPrimLinkable bp in m_children.Keys) | ||
480 | { | ||
481 | com += bp.Position; | ||
482 | } | ||
483 | com /= (m_children.Count + 1); | ||
484 | } | ||
485 | |||
486 | return com; | ||
487 | } | ||
488 | |||
489 | #region Extension | ||
490 | public virtual object Extension(string pFunct, params object[] pParams) | ||
491 | { | ||
492 | return null; | ||
493 | } | ||
494 | #endregion // Extension | ||
495 | |||
496 | // Invoke the detailed logger and output something if it's enabled. | ||
497 | protected void DetailLog(string msg, params Object[] args) | ||
498 | { | ||
499 | if (m_physicsScene.PhysicsLogging.Enabled) | ||
500 | m_physicsScene.DetailLog(msg, args); | ||
501 | } | ||
502 | } | ||
503 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs new file mode 100755 index 0000000..cae9efa --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs | |||
@@ -0,0 +1,477 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Framework; | ||
32 | |||
33 | using OMV = OpenMetaverse; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | |||
38 | public sealed class BSLinksetCompound : BSLinkset | ||
39 | { | ||
40 | #pragma warning disable 414 | ||
41 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | ||
42 | #pragma warning restore 414 | ||
43 | |||
44 | public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) | ||
45 | : base(scene, parent) | ||
46 | { | ||
47 | LinksetImpl = LinksetImplementation.Compound; | ||
48 | } | ||
49 | |||
50 | // ================================================================ | ||
51 | // Changing the physical property of the linkset only needs to change the root | ||
52 | public override void SetPhysicalFriction(float friction) | ||
53 | { | ||
54 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
55 | m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); | ||
56 | } | ||
57 | public override void SetPhysicalRestitution(float restitution) | ||
58 | { | ||
59 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
60 | m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); | ||
61 | } | ||
62 | public override void SetPhysicalGravity(OMV.Vector3 gravity) | ||
63 | { | ||
64 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
65 | m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); | ||
66 | } | ||
67 | public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) | ||
68 | { | ||
69 | OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass); | ||
70 | LinksetRoot.Inertia = inertia * inertiaFactor; | ||
71 | m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia); | ||
72 | m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); | ||
73 | } | ||
74 | public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) | ||
75 | { | ||
76 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
77 | m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); | ||
78 | } | ||
79 | public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags) | ||
80 | { | ||
81 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
82 | m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags); | ||
83 | } | ||
84 | public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) | ||
85 | { | ||
86 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
87 | m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); | ||
88 | } | ||
89 | // ================================================================ | ||
90 | |||
91 | // When physical properties are changed the linkset needs to recalculate | ||
92 | // its internal properties. | ||
93 | public override void Refresh(BSPrimLinkable requestor) | ||
94 | { | ||
95 | // Something changed so do the rebuilding thing | ||
96 | ScheduleRebuild(requestor); | ||
97 | base.Refresh(requestor); | ||
98 | } | ||
99 | |||
100 | // Schedule a refresh to happen after all the other taint processing. | ||
101 | private void ScheduleRebuild(BSPrimLinkable requestor) | ||
102 | { | ||
103 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | ||
104 | // If already rebuilding, don't request another rebuild. | ||
105 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. | ||
106 | lock (m_linksetActivityLock) | ||
107 | { | ||
108 | if (!RebuildScheduled && !Rebuilding && HasAnyChildren) | ||
109 | { | ||
110 | InternalScheduleRebuild(requestor); | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | |||
115 | // Must be called with m_linksetActivityLock or race conditions will haunt you. | ||
116 | private void InternalScheduleRebuild(BSPrimLinkable requestor) | ||
117 | { | ||
118 | DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}", | ||
119 | requestor.LocalID, Rebuilding, HasAnyChildren); | ||
120 | RebuildScheduled = true; | ||
121 | m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | ||
122 | { | ||
123 | if (HasAnyChildren) | ||
124 | { | ||
125 | if (this.AllPartsComplete) | ||
126 | { | ||
127 | RecomputeLinksetCompound(); | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete", | ||
132 | requestor.LocalID); | ||
133 | InternalScheduleRebuild(requestor); | ||
134 | } | ||
135 | } | ||
136 | RebuildScheduled = false; | ||
137 | }); | ||
138 | } | ||
139 | |||
140 | // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset. | ||
141 | // Only the state of the passed object can be modified. The rest of the linkset | ||
142 | // has not yet been fully constructed. | ||
143 | // Return 'true' if any properties updated on the passed object. | ||
144 | // Called at taint-time! | ||
145 | public override bool MakeDynamic(BSPrimLinkable child) | ||
146 | { | ||
147 | bool ret = false; | ||
148 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
149 | if (IsRoot(child)) | ||
150 | { | ||
151 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | ||
152 | Refresh(LinksetRoot); | ||
153 | } | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | // The object is going static (non-physical). We do not do anything for static linksets. | ||
158 | // Return 'true' if any properties updated on the passed object. | ||
159 | // Called at taint-time! | ||
160 | public override bool MakeStatic(BSPrimLinkable child) | ||
161 | { | ||
162 | bool ret = false; | ||
163 | |||
164 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
165 | child.ClearDisplacement(); | ||
166 | if (IsRoot(child)) | ||
167 | { | ||
168 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
169 | Refresh(LinksetRoot); | ||
170 | } | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. | ||
175 | // Called at taint-time. | ||
176 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) | ||
177 | { | ||
178 | if (!LinksetRoot.IsPhysicallyActive) | ||
179 | { | ||
180 | // No reason to do this physical stuff for static linksets. | ||
181 | DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | // The user moving a child around requires the rebuilding of the linkset compound shape | ||
186 | // One problem is this happens when a border is crossed -- the simulator implementation | ||
187 | // stores the position into the group which causes the move of the object | ||
188 | // but it also means all the child positions get updated. | ||
189 | // What would cause an unnecessary rebuild so we make sure the linkset is in a | ||
190 | // region before bothering to do a rebuild. | ||
191 | if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | ||
192 | { | ||
193 | // If a child of the linkset is updating only the position or rotation, that can be done | ||
194 | // without rebuilding the linkset. | ||
195 | // If a handle for the child can be fetch, we update the child here. If a rebuild was | ||
196 | // scheduled by someone else, the rebuild will just replace this setting. | ||
197 | |||
198 | bool updatedChild = false; | ||
199 | // Anything other than updating position or orientation usually means a physical update | ||
200 | // and that is caused by us updating the object. | ||
201 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | ||
202 | { | ||
203 | // Find the physical instance of the child | ||
204 | if (!RebuildScheduled // if rebuilding, let the rebuild do it | ||
205 | && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change | ||
206 | && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned | ||
207 | && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) | ||
208 | { | ||
209 | // It is possible that the linkset is still under construction and the child is not yet | ||
210 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will | ||
211 | // build the whole thing with the new position or rotation. | ||
212 | // The index must be checked because Bullet references the child array but does no validity | ||
213 | // checking of the child index passed. | ||
214 | int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); | ||
215 | if (updated.LinksetChildIndex < numLinksetChildren) | ||
216 | { | ||
217 | BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); | ||
218 | if (linksetChildShape.HasPhysicalShape) | ||
219 | { | ||
220 | // Found the child shape within the compound shape | ||
221 | m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, | ||
222 | updated.RawPosition - LinksetRoot.RawPosition, | ||
223 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | ||
224 | true /* shouldRecalculateLocalAabb */); | ||
225 | updatedChild = true; | ||
226 | DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}", | ||
227 | updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation); | ||
228 | } | ||
229 | else // DEBUG DEBUG | ||
230 | { // DEBUG DEBUG | ||
231 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", | ||
232 | updated.LocalID, linksetChildShape); | ||
233 | } // DEBUG DEBUG | ||
234 | } | ||
235 | else // DEBUG DEBUG | ||
236 | { // DEBUG DEBUG | ||
237 | // the child is not yet in the compound shape. This is non-fatal. | ||
238 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", | ||
239 | updated.LocalID, numLinksetChildren, updated.LinksetChildIndex); | ||
240 | } // DEBUG DEBUG | ||
241 | } | ||
242 | else // DEBUG DEBUG | ||
243 | { // DEBUG DEBUG | ||
244 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); | ||
245 | } // DEBUG DEBUG | ||
246 | |||
247 | if (!updatedChild) | ||
248 | { | ||
249 | // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. | ||
250 | // Note: there are several ways through this code that will not update the child if | ||
251 | // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since | ||
252 | // there will already be a rebuild scheduled. | ||
253 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", | ||
254 | updated.LocalID, whichUpdated); | ||
255 | Refresh(updated); | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | // Routine called when rebuilding the body of some member of the linkset. | ||
262 | // If one of the bodies is being changed, the linkset needs rebuilding. | ||
263 | // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated. | ||
264 | // Returns 'true' of something was actually removed and would need restoring | ||
265 | // Called at taint-time!! | ||
266 | public override bool RemoveDependencies(BSPrimLinkable child) | ||
267 | { | ||
268 | bool ret = false; | ||
269 | |||
270 | DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | ||
271 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); | ||
272 | |||
273 | Refresh(child); | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | // ================================================================ | ||
279 | |||
280 | // Add a new child to the linkset. | ||
281 | // Called while LinkActivity is locked. | ||
282 | protected override void AddChildToLinkset(BSPrimLinkable child) | ||
283 | { | ||
284 | if (!HasChild(child)) | ||
285 | { | ||
286 | m_children.Add(child, new BSLinkInfo(child)); | ||
287 | |||
288 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
289 | |||
290 | // Rebuild the compound shape with the new child shape included | ||
291 | Refresh(child); | ||
292 | } | ||
293 | return; | ||
294 | } | ||
295 | |||
296 | // Remove the specified child from the linkset. | ||
297 | // Safe to call even if the child is not really in the linkset. | ||
298 | protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) | ||
299 | { | ||
300 | child.ClearDisplacement(); | ||
301 | |||
302 | if (m_children.Remove(child)) | ||
303 | { | ||
304 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
305 | child.LocalID, | ||
306 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, | ||
307 | child.LocalID, child.PhysBody.AddrString); | ||
308 | |||
309 | // Cause the child's body to be rebuilt and thus restored to normal operation | ||
310 | child.ForceBodyShapeRebuild(inTaintTime); | ||
311 | |||
312 | if (!HasAnyChildren) | ||
313 | { | ||
314 | // The linkset is now empty. The root needs rebuilding. | ||
315 | LinksetRoot.ForceBodyShapeRebuild(inTaintTime); | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | // Rebuild the compound shape with the child removed | ||
320 | Refresh(LinksetRoot); | ||
321 | } | ||
322 | } | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | // Called before the simulation step to make sure the compound based linkset | ||
327 | // is all initialized. | ||
328 | // Constraint linksets are rebuilt every time. | ||
329 | // Note that this works for rebuilding just the root after a linkset is taken apart. | ||
330 | // Called at taint time!! | ||
331 | private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape | ||
332 | private void RecomputeLinksetCompound() | ||
333 | { | ||
334 | try | ||
335 | { | ||
336 | Rebuilding = true; | ||
337 | |||
338 | // No matter what is being done, force the root prim's PhysBody and PhysShape to get set | ||
339 | // to what they should be as if the root was not in a linkset. | ||
340 | // Not that bad since we only get into this routine if there are children in the linkset and | ||
341 | // something has been updated/changed. | ||
342 | // Have to do the rebuild before checking for physical because this might be a linkset | ||
343 | // being destructed and going non-physical. | ||
344 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
345 | |||
346 | // There is no reason to build all this physical stuff for a non-physical or empty linkset. | ||
347 | if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) | ||
348 | { | ||
349 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); | ||
350 | return; // Note the 'finally' clause at the botton which will get executed. | ||
351 | } | ||
352 | |||
353 | // Get a new compound shape to build the linkset shape in. | ||
354 | BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); | ||
355 | |||
356 | // Compute a displacement for each component so it is relative to the center-of-mass. | ||
357 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass | ||
358 | OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); | ||
359 | |||
360 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); | ||
361 | OMV.Vector3 origRootPosition = LinksetRoot.RawPosition; | ||
362 | |||
363 | // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass | ||
364 | OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | ||
365 | if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass) | ||
366 | { | ||
367 | // Zero everything if center-of-mass displacement is not being done. | ||
368 | centerDisplacementV = OMV.Vector3.Zero; | ||
369 | LinksetRoot.ClearDisplacement(); | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | // The actual center-of-mass could have been set by the user. | ||
374 | centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); | ||
375 | } | ||
376 | |||
377 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", | ||
378 | LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV); | ||
379 | |||
380 | // Add the shapes of all the components of the linkset | ||
381 | int memberIndex = 1; | ||
382 | ForEachMember((cPrim) => | ||
383 | { | ||
384 | if (IsRoot(cPrim)) | ||
385 | { | ||
386 | // Root shape is always index zero. | ||
387 | cPrim.LinksetChildIndex = 0; | ||
388 | } | ||
389 | else | ||
390 | { | ||
391 | cPrim.LinksetChildIndex = memberIndex; | ||
392 | memberIndex++; | ||
393 | } | ||
394 | |||
395 | // Get a reference to the shape of the child for adding of that shape to the linkset compound shape | ||
396 | BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); | ||
397 | |||
398 | // Offset the child shape from the center-of-mass and rotate it to root relative. | ||
399 | OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV; | ||
400 | OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; | ||
401 | |||
402 | // Add the child shape to the compound shape being built | ||
403 | if (childShape.physShapeInfo.HasPhysicalShape) | ||
404 | { | ||
405 | m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); | ||
406 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", | ||
407 | LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); | ||
408 | |||
409 | // Since we are borrowing the shape of the child, disable the origional child body | ||
410 | if (!IsRoot(cPrim)) | ||
411 | { | ||
412 | m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
413 | m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
414 | // We don't want collisions from the old linkset children. | ||
415 | m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
416 | cPrim.PhysBody.collisionType = CollisionType.LinksetChild; | ||
417 | } | ||
418 | } | ||
419 | else | ||
420 | { | ||
421 | // The linkset must be in an intermediate state where all the children have not yet | ||
422 | // been constructed. This sometimes happens on startup when everything is getting | ||
423 | // built and some shapes have to wait for assets to be read in. | ||
424 | // Just skip this linkset for the moment and cause the shape to be rebuilt next tick. | ||
425 | // One problem might be that the shape is broken somehow and it never becomes completely | ||
426 | // available. This might cause the rebuild to happen over and over. | ||
427 | InternalScheduleRebuild(LinksetRoot); | ||
428 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}", | ||
429 | LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); | ||
430 | // Output an annoying warning. It should only happen once but if it keeps coming out, | ||
431 | // the user knows there is something wrong and will report it. | ||
432 | m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader); | ||
433 | m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}", | ||
434 | LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape); | ||
435 | |||
436 | // This causes the loop to bail on building the rest of this linkset. | ||
437 | // The rebuild operation will fix it up next tick or declare the object unbuildable. | ||
438 | return true; | ||
439 | } | ||
440 | |||
441 | return false; // 'false' says to move onto the next child in the list | ||
442 | }); | ||
443 | |||
444 | // Replace the root shape with the built compound shape. | ||
445 | // Object removed and added to world to get collision cache rebuilt for new shape. | ||
446 | LinksetRoot.PhysShape.Dereference(m_physicsScene); | ||
447 | LinksetRoot.PhysShape = linksetShape; | ||
448 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
449 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); | ||
450 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
451 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", | ||
452 | LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); | ||
453 | |||
454 | // With all of the linkset packed into the root prim, it has the mass of everyone. | ||
455 | LinksetMass = ComputeLinksetMass(); | ||
456 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | ||
457 | |||
458 | if (UseBulletSimRootOffsetHack) | ||
459 | { | ||
460 | // Enable the physical position updator to return the position and rotation of the root shape. | ||
461 | // This enables a feature in the C++ code to return the world coordinates of the first shape in the | ||
462 | // compound shape. This aleviates the need to offset the returned physical position by the | ||
463 | // center-of-mass offset. | ||
464 | // TODO: either debug this feature or remove it. | ||
465 | m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | ||
466 | } | ||
467 | } | ||
468 | finally | ||
469 | { | ||
470 | Rebuilding = false; | ||
471 | } | ||
472 | |||
473 | // See that the Aabb surrounds the new shape | ||
474 | m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); | ||
475 | } | ||
476 | } | ||
477 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs new file mode 100755 index 0000000..4384cdc --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs | |||
@@ -0,0 +1,854 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Region.OptionalModules.Scripting; | ||
32 | |||
33 | using OMV = OpenMetaverse; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public sealed class BSLinksetConstraints : BSLinkset | ||
38 | { | ||
39 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | ||
40 | |||
41 | public class BSLinkInfoConstraint : BSLinkInfo | ||
42 | { | ||
43 | public ConstraintType constraintType; | ||
44 | public BSConstraint constraint; | ||
45 | public OMV.Vector3 linearLimitLow; | ||
46 | public OMV.Vector3 linearLimitHigh; | ||
47 | public OMV.Vector3 angularLimitLow; | ||
48 | public OMV.Vector3 angularLimitHigh; | ||
49 | public bool useFrameOffset; | ||
50 | public bool enableTransMotor; | ||
51 | public float transMotorMaxVel; | ||
52 | public float transMotorMaxForce; | ||
53 | public float cfm; | ||
54 | public float erp; | ||
55 | public float solverIterations; | ||
56 | // | ||
57 | public OMV.Vector3 frameInAloc; | ||
58 | public OMV.Quaternion frameInArot; | ||
59 | public OMV.Vector3 frameInBloc; | ||
60 | public OMV.Quaternion frameInBrot; | ||
61 | public bool useLinearReferenceFrameA; | ||
62 | // Spring | ||
63 | public bool[] springAxisEnable; | ||
64 | public float[] springDamping; | ||
65 | public float[] springStiffness; | ||
66 | public OMV.Vector3 springLinearEquilibriumPoint; | ||
67 | public OMV.Vector3 springAngularEquilibriumPoint; | ||
68 | |||
69 | public BSLinkInfoConstraint(BSPrimLinkable pMember) | ||
70 | : base(pMember) | ||
71 | { | ||
72 | constraint = null; | ||
73 | ResetLink(); | ||
74 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID); | ||
75 | } | ||
76 | |||
77 | // Set all the parameters for this constraint to a fixed, non-movable constraint. | ||
78 | public override void ResetLink() | ||
79 | { | ||
80 | // constraintType = ConstraintType.D6_CONSTRAINT_TYPE; | ||
81 | constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE; | ||
82 | linearLimitLow = OMV.Vector3.Zero; | ||
83 | linearLimitHigh = OMV.Vector3.Zero; | ||
84 | angularLimitLow = OMV.Vector3.Zero; | ||
85 | angularLimitHigh = OMV.Vector3.Zero; | ||
86 | useFrameOffset = BSParam.LinkConstraintUseFrameOffset; | ||
87 | enableTransMotor = BSParam.LinkConstraintEnableTransMotor; | ||
88 | transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; | ||
89 | transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; | ||
90 | cfm = BSParam.LinkConstraintCFM; | ||
91 | erp = BSParam.LinkConstraintERP; | ||
92 | solverIterations = BSParam.LinkConstraintSolverIterations; | ||
93 | frameInAloc = OMV.Vector3.Zero; | ||
94 | frameInArot = OMV.Quaternion.Identity; | ||
95 | frameInBloc = OMV.Vector3.Zero; | ||
96 | frameInBrot = OMV.Quaternion.Identity; | ||
97 | useLinearReferenceFrameA = true; | ||
98 | springAxisEnable = new bool[6]; | ||
99 | springDamping = new float[6]; | ||
100 | springStiffness = new float[6]; | ||
101 | for (int ii = 0; ii < springAxisEnable.Length; ii++) | ||
102 | { | ||
103 | springAxisEnable[ii] = false; | ||
104 | springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; | ||
105 | springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; | ||
106 | } | ||
107 | springLinearEquilibriumPoint = OMV.Vector3.Zero; | ||
108 | springAngularEquilibriumPoint = OMV.Vector3.Zero; | ||
109 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); | ||
110 | } | ||
111 | |||
112 | // Given a constraint, apply the current constraint parameters to same. | ||
113 | public override void SetLinkParameters(BSConstraint constrain) | ||
114 | { | ||
115 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType); | ||
116 | switch (constraintType) | ||
117 | { | ||
118 | case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: | ||
119 | case ConstraintType.D6_CONSTRAINT_TYPE: | ||
120 | BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; | ||
121 | if (constrain6dof != null) | ||
122 | { | ||
123 | // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code. | ||
124 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
125 | constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); | ||
126 | constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); | ||
127 | |||
128 | // tweek the constraint to increase stability | ||
129 | constrain6dof.UseFrameOffset(useFrameOffset); | ||
130 | constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); | ||
131 | constrain6dof.SetCFMAndERP(cfm, erp); | ||
132 | if (solverIterations != 0f) | ||
133 | { | ||
134 | constrain6dof.SetSolverIterations(solverIterations); | ||
135 | } | ||
136 | } | ||
137 | break; | ||
138 | case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: | ||
139 | BSConstraintSpring constrainSpring = constrain as BSConstraintSpring; | ||
140 | if (constrainSpring != null) | ||
141 | { | ||
142 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
143 | constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh); | ||
144 | constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh); | ||
145 | |||
146 | // tweek the constraint to increase stability | ||
147 | constrainSpring.UseFrameOffset(useFrameOffset); | ||
148 | constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); | ||
149 | constrainSpring.SetCFMAndERP(cfm, erp); | ||
150 | if (solverIterations != 0f) | ||
151 | { | ||
152 | constrainSpring.SetSolverIterations(solverIterations); | ||
153 | } | ||
154 | for (int ii = 0; ii < springAxisEnable.Length; ii++) | ||
155 | { | ||
156 | constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]); | ||
157 | if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) | ||
158 | constrainSpring.SetDamping(ii, springDamping[ii]); | ||
159 | if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) | ||
160 | constrainSpring.SetStiffness(ii, springStiffness[ii]); | ||
161 | } | ||
162 | constrainSpring.CalculateTransforms(); | ||
163 | |||
164 | if (springLinearEquilibriumPoint != OMV.Vector3.Zero) | ||
165 | constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint); | ||
166 | else | ||
167 | constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); | ||
168 | } | ||
169 | break; | ||
170 | default: | ||
171 | break; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | // Return 'true' if the property updates from the physics engine should be reported | ||
176 | // to the simulator. | ||
177 | // If the constraint is fixed, we don't need to report as the simulator and viewer will | ||
178 | // report the right things. | ||
179 | public override bool ShouldUpdateChildProperties() | ||
180 | { | ||
181 | bool ret = true; | ||
182 | if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE) | ||
183 | ret = false; | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) | ||
190 | { | ||
191 | LinksetImpl = LinksetImplementation.Constraint; | ||
192 | } | ||
193 | |||
194 | private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]"; | ||
195 | |||
196 | // When physical properties are changed the linkset needs to recalculate | ||
197 | // its internal properties. | ||
198 | // This is queued in the 'post taint' queue so the | ||
199 | // refresh will happen once after all the other taints are applied. | ||
200 | public override void Refresh(BSPrimLinkable requestor) | ||
201 | { | ||
202 | ScheduleRebuild(requestor); | ||
203 | base.Refresh(requestor); | ||
204 | |||
205 | } | ||
206 | |||
207 | private void ScheduleRebuild(BSPrimLinkable requestor) | ||
208 | { | ||
209 | DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", | ||
210 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); | ||
211 | |||
212 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | ||
213 | // If already rebuilding, don't request another rebuild. | ||
214 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. | ||
215 | lock (this) | ||
216 | { | ||
217 | if (!RebuildScheduled) | ||
218 | { | ||
219 | if (!Rebuilding && HasAnyChildren) | ||
220 | { | ||
221 | RebuildScheduled = true; | ||
222 | // Queue to happen after all the other taint processing | ||
223 | m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | ||
224 | { | ||
225 | if (HasAnyChildren) | ||
226 | { | ||
227 | // Constraints that have not been changed are not rebuild but make sure | ||
228 | // the constraint of the requestor is rebuilt. | ||
229 | PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); | ||
230 | // Rebuild the linkset and all its constraints. | ||
231 | RecomputeLinksetConstraints(); | ||
232 | } | ||
233 | RebuildScheduled = false; | ||
234 | }); | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | // The object is going dynamic (physical). Do any setup necessary | ||
241 | // for a dynamic linkset. | ||
242 | // Only the state of the passed object can be modified. The rest of the linkset | ||
243 | // has not yet been fully constructed. | ||
244 | // Return 'true' if any properties updated on the passed object. | ||
245 | // Called at taint-time! | ||
246 | public override bool MakeDynamic(BSPrimLinkable child) | ||
247 | { | ||
248 | bool ret = false; | ||
249 | DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
250 | if (IsRoot(child)) | ||
251 | { | ||
252 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | ||
253 | Refresh(LinksetRoot); | ||
254 | } | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | ||
259 | // Return 'true' if any properties updated on the passed object. | ||
260 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
261 | // world if it is a static linkset. | ||
262 | // Called at taint-time! | ||
263 | public override bool MakeStatic(BSPrimLinkable child) | ||
264 | { | ||
265 | bool ret = false; | ||
266 | |||
267 | DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
268 | child.ClearDisplacement(); | ||
269 | if (IsRoot(child)) | ||
270 | { | ||
271 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
272 | Refresh(LinksetRoot); | ||
273 | } | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | // Called at taint-time!! | ||
278 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj) | ||
279 | { | ||
280 | // Nothing to do for constraints on property updates | ||
281 | } | ||
282 | |||
283 | // Routine called when rebuilding the body of some member of the linkset. | ||
284 | // Destroy all the constraints have have been made to root and set | ||
285 | // up to rebuild the constraints before the next simulation step. | ||
286 | // Returns 'true' of something was actually removed and would need restoring | ||
287 | // Called at taint-time!! | ||
288 | public override bool RemoveDependencies(BSPrimLinkable child) | ||
289 | { | ||
290 | bool ret = false; | ||
291 | |||
292 | DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", | ||
293 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); | ||
294 | |||
295 | lock (m_linksetActivityLock) | ||
296 | { | ||
297 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. | ||
298 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | ||
299 | // Cause the constraints, et al to be rebuilt before the next simulation step. | ||
300 | Refresh(LinksetRoot); | ||
301 | } | ||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | // ================================================================ | ||
306 | |||
307 | // Add a new child to the linkset. | ||
308 | // Called while LinkActivity is locked. | ||
309 | protected override void AddChildToLinkset(BSPrimLinkable child) | ||
310 | { | ||
311 | if (!HasChild(child)) | ||
312 | { | ||
313 | m_children.Add(child, new BSLinkInfoConstraint(child)); | ||
314 | |||
315 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
316 | |||
317 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | ||
318 | Refresh(LinksetRoot); | ||
319 | } | ||
320 | return; | ||
321 | } | ||
322 | |||
323 | // Remove the specified child from the linkset. | ||
324 | // Safe to call even if the child is not really in my linkset. | ||
325 | protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) | ||
326 | { | ||
327 | if (m_children.Remove(child)) | ||
328 | { | ||
329 | BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now | ||
330 | BSPrimLinkable childx = child; | ||
331 | |||
332 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
333 | childx.LocalID, | ||
334 | rootx.LocalID, rootx.PhysBody.AddrString, | ||
335 | childx.LocalID, childx.PhysBody.AddrString); | ||
336 | |||
337 | m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() | ||
338 | { | ||
339 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | ||
340 | }); | ||
341 | // See that the linkset parameters are recomputed at the end of the taint time. | ||
342 | Refresh(LinksetRoot); | ||
343 | } | ||
344 | else | ||
345 | { | ||
346 | // Non-fatal occurance. | ||
347 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | ||
348 | } | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | // Create a constraint between me (root of linkset) and the passed prim (the child). | ||
353 | // Called at taint time! | ||
354 | private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) | ||
355 | { | ||
356 | // Don't build the constraint when asked. Put it off until just before the simulation step. | ||
357 | Refresh(rootPrim); | ||
358 | } | ||
359 | |||
360 | // Create a static constraint between the two passed objects | ||
361 | private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) | ||
362 | { | ||
363 | BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint; | ||
364 | if (linkInfo == null) | ||
365 | return null; | ||
366 | |||
367 | // Zero motion for children so they don't interpolate | ||
368 | li.member.ZeroMotion(true); | ||
369 | |||
370 | BSConstraint constrain = null; | ||
371 | |||
372 | switch (linkInfo.constraintType) | ||
373 | { | ||
374 | case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: | ||
375 | case ConstraintType.D6_CONSTRAINT_TYPE: | ||
376 | // Relative position normalized to the root prim | ||
377 | // Essentually a vector pointing from center of rootPrim to center of li.member | ||
378 | OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position; | ||
379 | |||
380 | // real world coordinate of midpoint between the two objects | ||
381 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | ||
382 | |||
383 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}", | ||
384 | rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody, | ||
385 | rootPrim.Position, linkInfo.member.Position, midPoint); | ||
386 | |||
387 | // create a constraint that allows no freedom of movement between the two objects | ||
388 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
389 | |||
390 | constrain = new BSConstraint6Dof( | ||
391 | m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true ); | ||
392 | |||
393 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | ||
394 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | ||
395 | * of the objects. | ||
396 | * Code left for future programmers. | ||
397 | // ================================================================================== | ||
398 | // relative position normalized to the root prim | ||
399 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | ||
400 | OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation; | ||
401 | |||
402 | // relative rotation of the child to the parent | ||
403 | OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation; | ||
404 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | ||
405 | |||
406 | DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID); | ||
407 | constrain = new BS6DofConstraint( | ||
408 | PhysicsScene.World, rootPrim.Body, liConstraint.member.Body, | ||
409 | OMV.Vector3.Zero, | ||
410 | OMV.Quaternion.Inverse(rootPrim.Orientation), | ||
411 | OMV.Vector3.Zero, | ||
412 | OMV.Quaternion.Inverse(liConstraint.member.Orientation), | ||
413 | true, | ||
414 | true | ||
415 | ); | ||
416 | // ================================================================================== | ||
417 | */ | ||
418 | |||
419 | break; | ||
420 | case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: | ||
421 | constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, | ||
422 | linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, | ||
423 | linkInfo.useLinearReferenceFrameA, | ||
424 | true /*disableCollisionsBetweenLinkedBodies*/); | ||
425 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}", | ||
426 | rootPrim.LocalID, | ||
427 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, | ||
428 | linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString, | ||
429 | rootPrim.Position, linkInfo.member.Position); | ||
430 | |||
431 | break; | ||
432 | default: | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | linkInfo.SetLinkParameters(constrain); | ||
437 | |||
438 | m_physicsScene.Constraints.AddConstraint(constrain); | ||
439 | |||
440 | return constrain; | ||
441 | } | ||
442 | |||
443 | // Remove linkage between the linkset root and a particular child | ||
444 | // The root and child bodies are passed in because we need to remove the constraint between | ||
445 | // the bodies that were present at unlink time. | ||
446 | // Called at taint time! | ||
447 | private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) | ||
448 | { | ||
449 | bool ret = false; | ||
450 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | ||
451 | rootPrim.LocalID, | ||
452 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, | ||
453 | childPrim.LocalID, childPrim.PhysBody.AddrString); | ||
454 | |||
455 | // If asked to unlink root from root, just remove all the constraints | ||
456 | if (rootPrim == childPrim || childPrim == LinksetRoot) | ||
457 | { | ||
458 | PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | ||
459 | ret = true; | ||
460 | } | ||
461 | else | ||
462 | { | ||
463 | // Find the constraint for this link and get rid of it from the overall collection and from my list | ||
464 | if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | ||
465 | { | ||
466 | // Make the child refresh its location | ||
467 | m_physicsScene.PE.PushUpdate(childPrim.PhysBody); | ||
468 | ret = true; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | // Remove linkage between myself and any possible children I might have. | ||
476 | // Returns 'true' of any constraints were destroyed. | ||
477 | // Called at taint time! | ||
478 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim) | ||
479 | { | ||
480 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | ||
481 | |||
482 | return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); | ||
483 | } | ||
484 | |||
485 | // Call each of the constraints that make up this linkset and recompute the | ||
486 | // various transforms and variables. Create constraints of not created yet. | ||
487 | // Called before the simulation step to make sure the constraint based linkset | ||
488 | // is all initialized. | ||
489 | // Called at taint time!! | ||
490 | private void RecomputeLinksetConstraints() | ||
491 | { | ||
492 | float linksetMass = LinksetMass; | ||
493 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); | ||
494 | |||
495 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", | ||
496 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); | ||
497 | |||
498 | try | ||
499 | { | ||
500 | Rebuilding = true; | ||
501 | |||
502 | // There is no reason to build all this physical stuff for a non-physical linkset. | ||
503 | if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) | ||
504 | { | ||
505 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); | ||
506 | return; // Note the 'finally' clause at the botton which will get executed. | ||
507 | } | ||
508 | |||
509 | ForEachLinkInfo((li) => | ||
510 | { | ||
511 | // A child in the linkset physically shows the mass of the whole linkset. | ||
512 | // This allows Bullet to apply enough force on the child to move the whole linkset. | ||
513 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) | ||
514 | li.member.UpdatePhysicalMassProperties(linksetMass, true); | ||
515 | |||
516 | BSConstraint constrain; | ||
517 | if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain)) | ||
518 | { | ||
519 | // If constraint doesn't exist yet, create it. | ||
520 | constrain = BuildConstraint(LinksetRoot, li); | ||
521 | } | ||
522 | li.SetLinkParameters(constrain); | ||
523 | constrain.RecomputeConstraintVariables(linksetMass); | ||
524 | |||
525 | // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG | ||
526 | return false; // 'false' says to keep processing other members | ||
527 | }); | ||
528 | } | ||
529 | finally | ||
530 | { | ||
531 | Rebuilding = false; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | #region Extension | ||
536 | public override object Extension(string pFunct, params object[] pParams) | ||
537 | { | ||
538 | object ret = null; | ||
539 | switch (pFunct) | ||
540 | { | ||
541 | // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] | ||
542 | case ExtendedPhysics.PhysFunctChangeLinkType: | ||
543 | if (pParams.Length > 2) | ||
544 | { | ||
545 | int requestedType = (int)pParams[2]; | ||
546 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); | ||
547 | if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE | ||
548 | || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE | ||
549 | || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE | ||
550 | || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE | ||
551 | || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE | ||
552 | || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE) | ||
553 | { | ||
554 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
555 | if (child != null) | ||
556 | { | ||
557 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}", | ||
558 | LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType); | ||
559 | m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate() | ||
560 | { | ||
561 | // Pick up all the constraints currently created. | ||
562 | RemoveDependencies(child); | ||
563 | |||
564 | BSLinkInfo linkInfo = null; | ||
565 | if (TryGetLinkInfo(child, out linkInfo)) | ||
566 | { | ||
567 | BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; | ||
568 | if (linkInfoC != null) | ||
569 | { | ||
570 | linkInfoC.constraintType = (ConstraintType)requestedType; | ||
571 | ret = (object)true; | ||
572 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}", | ||
573 | linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); | ||
574 | } | ||
575 | else | ||
576 | { | ||
577 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); | ||
578 | } | ||
579 | } | ||
580 | else | ||
581 | { | ||
582 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); | ||
583 | } | ||
584 | // Cause the whole linkset to be rebuilt in post-taint time. | ||
585 | Refresh(child); | ||
586 | }); | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID); | ||
591 | } | ||
592 | } | ||
593 | else | ||
594 | { | ||
595 | DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}", | ||
596 | LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE)); | ||
597 | } | ||
598 | } | ||
599 | break; | ||
600 | // pParams = [ BSPhysObject root, BSPhysObject child ] | ||
601 | case ExtendedPhysics.PhysFunctGetLinkType: | ||
602 | if (pParams.Length > 0) | ||
603 | { | ||
604 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
605 | if (child != null) | ||
606 | { | ||
607 | BSLinkInfo linkInfo = null; | ||
608 | if (TryGetLinkInfo(child, out linkInfo)) | ||
609 | { | ||
610 | BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; | ||
611 | if (linkInfoC != null) | ||
612 | { | ||
613 | ret = (object)(int)linkInfoC.constraintType; | ||
614 | DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}", | ||
615 | linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); | ||
616 | |||
617 | } | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | break; | ||
622 | // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ] | ||
623 | case ExtendedPhysics.PhysFunctChangeLinkParams: | ||
624 | // There should be two parameters: the childActor and a list of parameters to set | ||
625 | if (pParams.Length > 2) | ||
626 | { | ||
627 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
628 | BSLinkInfo baseLinkInfo = null; | ||
629 | if (TryGetLinkInfo(child, out baseLinkInfo)) | ||
630 | { | ||
631 | BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; | ||
632 | if (linkInfo != null) | ||
633 | { | ||
634 | int valueInt; | ||
635 | float valueFloat; | ||
636 | bool valueBool; | ||
637 | OMV.Vector3 valueVector; | ||
638 | OMV.Vector3 valueVector2; | ||
639 | OMV.Quaternion valueQuaternion; | ||
640 | int axisLow, axisHigh; | ||
641 | |||
642 | int opIndex = 2; | ||
643 | while (opIndex < pParams.Length) | ||
644 | { | ||
645 | int thisOp = 0; | ||
646 | string errMsg = ""; | ||
647 | try | ||
648 | { | ||
649 | thisOp = (int)pParams[opIndex]; | ||
650 | DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}", | ||
651 | linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]); | ||
652 | switch (thisOp) | ||
653 | { | ||
654 | case ExtendedPhysics.PHYS_PARAM_LINK_TYPE: | ||
655 | valueInt = (int)pParams[opIndex + 1]; | ||
656 | ConstraintType valueType = (ConstraintType)valueInt; | ||
657 | if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE | ||
658 | || valueType == ConstraintType.D6_CONSTRAINT_TYPE | ||
659 | || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE | ||
660 | || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE | ||
661 | || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE | ||
662 | || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE) | ||
663 | { | ||
664 | linkInfo.constraintType = valueType; | ||
665 | } | ||
666 | opIndex += 2; | ||
667 | break; | ||
668 | case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: | ||
669 | errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector"; | ||
670 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
671 | linkInfo.frameInAloc = valueVector; | ||
672 | opIndex += 2; | ||
673 | break; | ||
674 | case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: | ||
675 | errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation"; | ||
676 | valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; | ||
677 | linkInfo.frameInArot = valueQuaternion; | ||
678 | opIndex += 2; | ||
679 | break; | ||
680 | case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: | ||
681 | errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector"; | ||
682 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
683 | linkInfo.frameInBloc = valueVector; | ||
684 | opIndex += 2; | ||
685 | break; | ||
686 | case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: | ||
687 | errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation"; | ||
688 | valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; | ||
689 | linkInfo.frameInBrot = valueQuaternion; | ||
690 | opIndex += 2; | ||
691 | break; | ||
692 | case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: | ||
693 | errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector"; | ||
694 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
695 | linkInfo.linearLimitLow = valueVector; | ||
696 | opIndex += 2; | ||
697 | break; | ||
698 | case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: | ||
699 | errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector"; | ||
700 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
701 | linkInfo.linearLimitHigh = valueVector; | ||
702 | opIndex += 2; | ||
703 | break; | ||
704 | case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: | ||
705 | errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector"; | ||
706 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
707 | linkInfo.angularLimitLow = valueVector; | ||
708 | opIndex += 2; | ||
709 | break; | ||
710 | case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: | ||
711 | errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector"; | ||
712 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
713 | linkInfo.angularLimitHigh = valueVector; | ||
714 | opIndex += 2; | ||
715 | break; | ||
716 | case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: | ||
717 | errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)"; | ||
718 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
719 | linkInfo.useFrameOffset = valueBool; | ||
720 | opIndex += 2; | ||
721 | break; | ||
722 | case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: | ||
723 | errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)"; | ||
724 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
725 | linkInfo.enableTransMotor = valueBool; | ||
726 | opIndex += 2; | ||
727 | break; | ||
728 | case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: | ||
729 | errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float"; | ||
730 | valueFloat = (float)pParams[opIndex + 1]; | ||
731 | linkInfo.transMotorMaxVel = valueFloat; | ||
732 | opIndex += 2; | ||
733 | break; | ||
734 | case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: | ||
735 | errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float"; | ||
736 | valueFloat = (float)pParams[opIndex + 1]; | ||
737 | linkInfo.transMotorMaxForce = valueFloat; | ||
738 | opIndex += 2; | ||
739 | break; | ||
740 | case ExtendedPhysics.PHYS_PARAM_CFM: | ||
741 | errMsg = "PHYS_PARAM_CFM takes one parameter of type float"; | ||
742 | valueFloat = (float)pParams[opIndex + 1]; | ||
743 | linkInfo.cfm = valueFloat; | ||
744 | opIndex += 2; | ||
745 | break; | ||
746 | case ExtendedPhysics.PHYS_PARAM_ERP: | ||
747 | errMsg = "PHYS_PARAM_ERP takes one parameter of type float"; | ||
748 | valueFloat = (float)pParams[opIndex + 1]; | ||
749 | linkInfo.erp = valueFloat; | ||
750 | opIndex += 2; | ||
751 | break; | ||
752 | case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: | ||
753 | errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float"; | ||
754 | valueFloat = (float)pParams[opIndex + 1]; | ||
755 | linkInfo.solverIterations = valueFloat; | ||
756 | opIndex += 2; | ||
757 | break; | ||
758 | case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: | ||
759 | errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)"; | ||
760 | valueInt = (int)pParams[opIndex + 1]; | ||
761 | valueBool = ((int)pParams[opIndex + 2]) != 0; | ||
762 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
763 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
764 | linkInfo.springAxisEnable[ii] = valueBool; | ||
765 | opIndex += 3; | ||
766 | break; | ||
767 | case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: | ||
768 | errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float"; | ||
769 | valueInt = (int)pParams[opIndex + 1]; | ||
770 | valueFloat = (float)pParams[opIndex + 2]; | ||
771 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
772 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
773 | linkInfo.springDamping[ii] = valueFloat; | ||
774 | opIndex += 3; | ||
775 | break; | ||
776 | case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: | ||
777 | errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float"; | ||
778 | valueInt = (int)pParams[opIndex + 1]; | ||
779 | valueFloat = (float)pParams[opIndex + 2]; | ||
780 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
781 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
782 | linkInfo.springStiffness[ii] = valueFloat; | ||
783 | opIndex += 3; | ||
784 | break; | ||
785 | case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT: | ||
786 | errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector"; | ||
787 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
788 | valueVector2 = (OMV.Vector3)pParams[opIndex + 2]; | ||
789 | linkInfo.springLinearEquilibriumPoint = valueVector; | ||
790 | linkInfo.springAngularEquilibriumPoint = valueVector2; | ||
791 | opIndex += 3; | ||
792 | break; | ||
793 | case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: | ||
794 | errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)"; | ||
795 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
796 | linkInfo.useLinearReferenceFrameA = valueBool; | ||
797 | opIndex += 2; | ||
798 | break; | ||
799 | default: | ||
800 | break; | ||
801 | } | ||
802 | } | ||
803 | catch (InvalidCastException e) | ||
804 | { | ||
805 | m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}", | ||
806 | LogHeader, errMsg, e); | ||
807 | } | ||
808 | catch (Exception e) | ||
809 | { | ||
810 | m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); | ||
811 | } | ||
812 | } | ||
813 | } | ||
814 | // Something changed so a rebuild is in order | ||
815 | Refresh(child); | ||
816 | } | ||
817 | } | ||
818 | break; | ||
819 | default: | ||
820 | ret = base.Extension(pFunct, pParams); | ||
821 | break; | ||
822 | } | ||
823 | return ret; | ||
824 | } | ||
825 | |||
826 | // Bullet constraints keep some limit parameters for each linear and angular axis. | ||
827 | // Setting same is easier if there is an easy way to see all or types. | ||
828 | // This routine returns the array limits for the set of axis. | ||
829 | private void GetAxisRange(int rangeSpec, out int low, out int high) | ||
830 | { | ||
831 | switch (rangeSpec) | ||
832 | { | ||
833 | case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL: | ||
834 | low = 0; | ||
835 | high = 2; | ||
836 | break; | ||
837 | case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL: | ||
838 | low = 3; | ||
839 | high = 5; | ||
840 | break; | ||
841 | case ExtendedPhysics.PHYS_AXIS_ALL: | ||
842 | low = 0; | ||
843 | high = 5; | ||
844 | break; | ||
845 | default: | ||
846 | low = high = rangeSpec; | ||
847 | break; | ||
848 | } | ||
849 | return; | ||
850 | } | ||
851 | #endregion // Extension | ||
852 | |||
853 | } | ||
854 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs new file mode 100755 index 0000000..ee77d6e --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs | |||
@@ -0,0 +1,203 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | |||
36 | public struct MaterialAttributes | ||
37 | { | ||
38 | // Material type values that correspond with definitions for LSL | ||
39 | public enum Material : int | ||
40 | { | ||
41 | Stone = 0, | ||
42 | Metal, | ||
43 | Glass, | ||
44 | Wood, | ||
45 | Flesh, | ||
46 | Plastic, | ||
47 | Rubber, | ||
48 | Light, | ||
49 | // Hereafter are BulletSim additions | ||
50 | Avatar, | ||
51 | NumberOfTypes // the count of types in the enum. | ||
52 | } | ||
53 | |||
54 | // Names must be in the order of the above enum. | ||
55 | // These names must coorespond to the lower case field names in the MaterialAttributes | ||
56 | // structure as reflection is used to select the field to put the value in. | ||
57 | public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; | ||
58 | |||
59 | public MaterialAttributes(string t, float d, float f, float r) | ||
60 | { | ||
61 | type = t; | ||
62 | density = d; | ||
63 | friction = f; | ||
64 | restitution = r; | ||
65 | } | ||
66 | public string type; | ||
67 | public float density; | ||
68 | public float friction; | ||
69 | public float restitution; | ||
70 | } | ||
71 | |||
72 | public static class BSMaterials | ||
73 | { | ||
74 | // Attributes for each material type | ||
75 | private static readonly MaterialAttributes[] Attributes; | ||
76 | |||
77 | // Map of material name to material type code | ||
78 | public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap; | ||
79 | |||
80 | static BSMaterials() | ||
81 | { | ||
82 | // Attribute sets for both the non-physical and physical instances of materials. | ||
83 | Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; | ||
84 | |||
85 | // Map of name to type code. | ||
86 | MaterialMap = new Dictionary<string, MaterialAttributes.Material>(); | ||
87 | MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); | ||
88 | MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); | ||
89 | MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); | ||
90 | MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); | ||
91 | MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); | ||
92 | MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); | ||
93 | MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); | ||
94 | MaterialMap.Add("Light", MaterialAttributes.Material.Light); | ||
95 | MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); | ||
96 | } | ||
97 | |||
98 | // This is where all the default material attributes are defined. | ||
99 | public static void InitializeFromDefaults(ConfigurationParameters parms) | ||
100 | { | ||
101 | // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL | ||
102 | float dDensity = parms.defaultDensity; | ||
103 | float dFriction = parms.defaultFriction; | ||
104 | float dRestitution = parms.defaultRestitution; | ||
105 | Attributes[(int)MaterialAttributes.Material.Stone] = | ||
106 | new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); | ||
107 | Attributes[(int)MaterialAttributes.Material.Metal] = | ||
108 | new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); | ||
109 | Attributes[(int)MaterialAttributes.Material.Glass] = | ||
110 | new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); | ||
111 | Attributes[(int)MaterialAttributes.Material.Wood] = | ||
112 | new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); | ||
113 | Attributes[(int)MaterialAttributes.Material.Flesh] = | ||
114 | new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); | ||
115 | Attributes[(int)MaterialAttributes.Material.Plastic] = | ||
116 | new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); | ||
117 | Attributes[(int)MaterialAttributes.Material.Rubber] = | ||
118 | new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); | ||
119 | Attributes[(int)MaterialAttributes.Material.Light] = | ||
120 | new MaterialAttributes("light",dDensity, dFriction, dRestitution); | ||
121 | Attributes[(int)MaterialAttributes.Material.Avatar] = | ||
122 | new MaterialAttributes("avatar",3.5f, 0.2f, 0f); | ||
123 | |||
124 | Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
125 | new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); | ||
126 | Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
127 | new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f); | ||
128 | Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
129 | new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f); | ||
130 | Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
131 | new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f); | ||
132 | Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
133 | new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f); | ||
134 | Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
135 | new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f); | ||
136 | Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
137 | new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f); | ||
138 | Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
139 | new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); | ||
140 | Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
141 | new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f); | ||
142 | } | ||
143 | |||
144 | // Under the [BulletSim] section, one can change the individual material | ||
145 | // attribute values. The format of the configuration parameter is: | ||
146 | // <materialName><Attribute>["Physical"] = floatValue | ||
147 | // For instance: | ||
148 | // [BulletSim] | ||
149 | // StoneFriction = 0.2 | ||
150 | // FleshRestitutionPhysical = 0.8 | ||
151 | // Materials can have different parameters for their static and | ||
152 | // physical instantiations. When setting the non-physical value, | ||
153 | // both values are changed. Setting the physical value only changes | ||
154 | // the physical value. | ||
155 | public static void InitializefromParameters(IConfig pConfig) | ||
156 | { | ||
157 | foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap) | ||
158 | { | ||
159 | string matName = kvp.Key; | ||
160 | foreach (string attribName in MaterialAttributes.MaterialAttribs) | ||
161 | { | ||
162 | string paramName = matName + attribName; | ||
163 | if (pConfig.Contains(paramName)) | ||
164 | { | ||
165 | float paramValue = pConfig.GetFloat(paramName); | ||
166 | SetAttributeValue((int)kvp.Value, attribName, paramValue); | ||
167 | // set the physical value also | ||
168 | SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
169 | } | ||
170 | paramName += "Physical"; | ||
171 | if (pConfig.Contains(paramName)) | ||
172 | { | ||
173 | float paramValue = pConfig.GetFloat(paramName); | ||
174 | SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | // Use reflection to set the value in the attribute structure. | ||
181 | private static void SetAttributeValue(int matType, string attribName, float val) | ||
182 | { | ||
183 | // Get the current attribute values for this material | ||
184 | MaterialAttributes thisAttrib = Attributes[matType]; | ||
185 | // Find the field for the passed attribute name (eg, find field named 'friction') | ||
186 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); | ||
187 | if (fieldInfo != null) | ||
188 | { | ||
189 | fieldInfo.SetValue(thisAttrib, val); | ||
190 | // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference. | ||
191 | Attributes[matType] = thisAttrib; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | // Given a material type, return a structure of attributes. | ||
196 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) | ||
197 | { | ||
198 | int ind = (int)type; | ||
199 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; | ||
200 | return Attributes[ind]; | ||
201 | } | ||
202 | } | ||
203 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs new file mode 100755 index 0000000..7693195 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs | |||
@@ -0,0 +1,451 @@ | |||
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.Text; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | |||
34 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
35 | { | ||
36 | public abstract class BSMotor | ||
37 | { | ||
38 | // Timescales and other things can be turned off by setting them to 'infinite'. | ||
39 | public const float Infinite = 12345.6f; | ||
40 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); | ||
41 | |||
42 | public BSMotor(string useName) | ||
43 | { | ||
44 | UseName = useName; | ||
45 | PhysicsScene = null; | ||
46 | Enabled = true; | ||
47 | } | ||
48 | public virtual bool Enabled { get; set; } | ||
49 | public virtual void Reset() { } | ||
50 | public virtual void Zero() { } | ||
51 | public virtual void GenerateTestOutput(float timeStep) { } | ||
52 | |||
53 | // A name passed at motor creation for easily identifyable debugging messages. | ||
54 | public string UseName { get; private set; } | ||
55 | |||
56 | // Used only for outputting debug information. Might not be set so check for null. | ||
57 | public BSScene PhysicsScene { get; set; } | ||
58 | protected void MDetailLog(string msg, params Object[] parms) | ||
59 | { | ||
60 | if (PhysicsScene != null) | ||
61 | { | ||
62 | PhysicsScene.DetailLog(msg, parms); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. | ||
68 | // The TargetValue decays in TargetValueDecayTimeScale. | ||
69 | // This motor will "zero itself" over time in that the targetValue will | ||
70 | // decay to zero and the currentValue will follow it to that zero. | ||
71 | // The overall effect is for the returned correction value to go from large | ||
72 | // values to small and eventually zero values. | ||
73 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. | ||
74 | |||
75 | // For instance, if something is moving at speed X and the desired speed is Y, | ||
76 | // CurrentValue is X and TargetValue is Y. As the motor is stepped, new | ||
77 | // values of CurrentValue are returned that approach the TargetValue. | ||
78 | // The feature of decaying TargetValue is so vehicles will eventually | ||
79 | // come to a stop rather than run forever. This can be disabled by | ||
80 | // setting TargetValueDecayTimescale to 'infinite'. | ||
81 | // The change from CurrentValue to TargetValue is linear over TimeScale seconds. | ||
82 | public class BSVMotor : BSMotor | ||
83 | { | ||
84 | // public Vector3 FrameOfReference { get; set; } | ||
85 | // public Vector3 Offset { get; set; } | ||
86 | |||
87 | public virtual float TimeScale { get; set; } | ||
88 | public virtual float TargetValueDecayTimeScale { get; set; } | ||
89 | public virtual float Efficiency { get; set; } | ||
90 | |||
91 | public virtual float ErrorZeroThreshold { get; set; } | ||
92 | |||
93 | public virtual Vector3 TargetValue { get; protected set; } | ||
94 | public virtual Vector3 CurrentValue { get; protected set; } | ||
95 | public virtual Vector3 LastError { get; protected set; } | ||
96 | |||
97 | public virtual bool ErrorIsZero() | ||
98 | { | ||
99 | return ErrorIsZero(LastError); | ||
100 | } | ||
101 | public virtual bool ErrorIsZero(Vector3 err) | ||
102 | { | ||
103 | return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); | ||
104 | } | ||
105 | |||
106 | public BSVMotor(string useName) | ||
107 | : base(useName) | ||
108 | { | ||
109 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | ||
110 | Efficiency = 1f; | ||
111 | CurrentValue = TargetValue = Vector3.Zero; | ||
112 | ErrorZeroThreshold = 0.001f; | ||
113 | } | ||
114 | public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency) | ||
115 | : this(useName) | ||
116 | { | ||
117 | TimeScale = timeScale; | ||
118 | TargetValueDecayTimeScale = decayTimeScale; | ||
119 | Efficiency = efficiency; | ||
120 | CurrentValue = TargetValue = Vector3.Zero; | ||
121 | } | ||
122 | public void SetCurrent(Vector3 current) | ||
123 | { | ||
124 | CurrentValue = current; | ||
125 | } | ||
126 | public void SetTarget(Vector3 target) | ||
127 | { | ||
128 | TargetValue = target; | ||
129 | } | ||
130 | public override void Zero() | ||
131 | { | ||
132 | base.Zero(); | ||
133 | CurrentValue = TargetValue = Vector3.Zero; | ||
134 | } | ||
135 | |||
136 | // Compute the next step and return the new current value. | ||
137 | // Returns the correction needed to move 'current' to 'target'. | ||
138 | public virtual Vector3 Step(float timeStep) | ||
139 | { | ||
140 | if (!Enabled) return TargetValue; | ||
141 | |||
142 | Vector3 origTarget = TargetValue; // DEBUG | ||
143 | Vector3 origCurrVal = CurrentValue; // DEBUG | ||
144 | |||
145 | Vector3 correction = Vector3.Zero; | ||
146 | Vector3 error = TargetValue - CurrentValue; | ||
147 | if (!ErrorIsZero(error)) | ||
148 | { | ||
149 | correction = StepError(timeStep, error); | ||
150 | |||
151 | CurrentValue += correction; | ||
152 | |||
153 | // The desired value reduces to zero which also reduces the difference with current. | ||
154 | // If the decay time is infinite, don't decay at all. | ||
155 | float decayFactor = 0f; | ||
156 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
157 | { | ||
158 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
159 | TargetValue *= (1f - decayFactor); | ||
160 | } | ||
161 | |||
162 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | ||
163 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
164 | timeStep, error, correction); | ||
165 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", | ||
166 | BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | // Difference between what we have and target is small. Motor is done. | ||
171 | if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||
172 | { | ||
173 | // The target can step down to nearly zero but not get there. If close to zero | ||
174 | // it is really zero. | ||
175 | TargetValue = Vector3.Zero; | ||
176 | } | ||
177 | CurrentValue = TargetValue; | ||
178 | MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}", | ||
179 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue); | ||
180 | } | ||
181 | LastError = error; | ||
182 | |||
183 | return correction; | ||
184 | } | ||
185 | // version of step that sets the current value before doing the step | ||
186 | public virtual Vector3 Step(float timeStep, Vector3 current) | ||
187 | { | ||
188 | CurrentValue = current; | ||
189 | return Step(timeStep); | ||
190 | } | ||
191 | // Given and error, computer a correction for this step. | ||
192 | // Simple scaling of the error by the timestep. | ||
193 | public virtual Vector3 StepError(float timeStep, Vector3 error) | ||
194 | { | ||
195 | if (!Enabled) return Vector3.Zero; | ||
196 | |||
197 | Vector3 returnCorrection = Vector3.Zero; | ||
198 | if (!ErrorIsZero(error)) | ||
199 | { | ||
200 | // correction = error / secondsItShouldTakeToCorrect | ||
201 | Vector3 correctionAmount; | ||
202 | if (TimeScale == 0f || TimeScale == BSMotor.Infinite) | ||
203 | correctionAmount = error * timeStep; | ||
204 | else | ||
205 | correctionAmount = error / TimeScale * timeStep; | ||
206 | |||
207 | returnCorrection = correctionAmount; | ||
208 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", | ||
209 | BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); | ||
210 | } | ||
211 | return returnCorrection; | ||
212 | } | ||
213 | |||
214 | // The user sets all the parameters and calls this which outputs values until error is zero. | ||
215 | public override void GenerateTestOutput(float timeStep) | ||
216 | { | ||
217 | // maximum number of outputs to generate. | ||
218 | int maxOutput = 50; | ||
219 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); | ||
220 | MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}", | ||
221 | BSScene.DetailLogZero, UseName, | ||
222 | TimeScale, TargetValueDecayTimeScale, Efficiency, | ||
223 | CurrentValue, TargetValue); | ||
224 | |||
225 | LastError = BSMotor.InfiniteVector; | ||
226 | while (maxOutput-- > 0 && !ErrorIsZero()) | ||
227 | { | ||
228 | Vector3 lastStep = Step(timeStep); | ||
229 | MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", | ||
230 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); | ||
231 | } | ||
232 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); | ||
233 | |||
234 | |||
235 | } | ||
236 | |||
237 | public override string ToString() | ||
238 | { | ||
239 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", | ||
240 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | // ============================================================================ | ||
245 | // ============================================================================ | ||
246 | public class BSFMotor : BSMotor | ||
247 | { | ||
248 | public virtual float TimeScale { get; set; } | ||
249 | public virtual float TargetValueDecayTimeScale { get; set; } | ||
250 | public virtual float Efficiency { get; set; } | ||
251 | |||
252 | public virtual float ErrorZeroThreshold { get; set; } | ||
253 | |||
254 | public virtual float TargetValue { get; protected set; } | ||
255 | public virtual float CurrentValue { get; protected set; } | ||
256 | public virtual float LastError { get; protected set; } | ||
257 | |||
258 | public virtual bool ErrorIsZero() | ||
259 | { | ||
260 | return ErrorIsZero(LastError); | ||
261 | } | ||
262 | public virtual bool ErrorIsZero(float err) | ||
263 | { | ||
264 | return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); | ||
265 | } | ||
266 | |||
267 | public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency) | ||
268 | : base(useName) | ||
269 | { | ||
270 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | ||
271 | Efficiency = 1f; | ||
272 | CurrentValue = TargetValue = 0f; | ||
273 | ErrorZeroThreshold = 0.01f; | ||
274 | } | ||
275 | public void SetCurrent(float current) | ||
276 | { | ||
277 | CurrentValue = current; | ||
278 | } | ||
279 | public void SetTarget(float target) | ||
280 | { | ||
281 | TargetValue = target; | ||
282 | } | ||
283 | public override void Zero() | ||
284 | { | ||
285 | base.Zero(); | ||
286 | CurrentValue = TargetValue = 0f; | ||
287 | } | ||
288 | |||
289 | public virtual float Step(float timeStep) | ||
290 | { | ||
291 | if (!Enabled) return TargetValue; | ||
292 | |||
293 | float origTarget = TargetValue; // DEBUG | ||
294 | float origCurrVal = CurrentValue; // DEBUG | ||
295 | |||
296 | float correction = 0f; | ||
297 | float error = TargetValue - CurrentValue; | ||
298 | if (!ErrorIsZero(error)) | ||
299 | { | ||
300 | correction = StepError(timeStep, error); | ||
301 | |||
302 | CurrentValue += correction; | ||
303 | |||
304 | // The desired value reduces to zero which also reduces the difference with current. | ||
305 | // If the decay time is infinite, don't decay at all. | ||
306 | float decayFactor = 0f; | ||
307 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
308 | { | ||
309 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
310 | TargetValue *= (1f - decayFactor); | ||
311 | } | ||
312 | |||
313 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | ||
314 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
315 | timeStep, error, correction); | ||
316 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", | ||
317 | BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); | ||
318 | } | ||
319 | else | ||
320 | { | ||
321 | // Difference between what we have and target is small. Motor is done. | ||
322 | if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold)) | ||
323 | { | ||
324 | // The target can step down to nearly zero but not get there. If close to zero | ||
325 | // it is really zero. | ||
326 | TargetValue = 0f; | ||
327 | } | ||
328 | CurrentValue = TargetValue; | ||
329 | MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", | ||
330 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); | ||
331 | } | ||
332 | LastError = error; | ||
333 | |||
334 | return CurrentValue; | ||
335 | } | ||
336 | |||
337 | public virtual float StepError(float timeStep, float error) | ||
338 | { | ||
339 | if (!Enabled) return 0f; | ||
340 | |||
341 | float returnCorrection = 0f; | ||
342 | if (!ErrorIsZero(error)) | ||
343 | { | ||
344 | // correction = error / secondsItShouldTakeToCorrect | ||
345 | float correctionAmount; | ||
346 | if (TimeScale == 0f || TimeScale == BSMotor.Infinite) | ||
347 | correctionAmount = error * timeStep; | ||
348 | else | ||
349 | correctionAmount = error / TimeScale * timeStep; | ||
350 | |||
351 | returnCorrection = correctionAmount; | ||
352 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", | ||
353 | BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); | ||
354 | } | ||
355 | return returnCorrection; | ||
356 | } | ||
357 | |||
358 | public override string ToString() | ||
359 | { | ||
360 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", | ||
361 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); | ||
362 | } | ||
363 | |||
364 | } | ||
365 | |||
366 | // ============================================================================ | ||
367 | // ============================================================================ | ||
368 | // Proportional, Integral, Derivitive ("PID") Motor | ||
369 | // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. | ||
370 | public class BSPIDVMotor : BSVMotor | ||
371 | { | ||
372 | // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. | ||
373 | public Vector3 proportionFactor { get; set; } | ||
374 | public Vector3 integralFactor { get; set; } | ||
375 | public Vector3 derivFactor { get; set; } | ||
376 | |||
377 | // The factors are vectors for the three dimensions. This is the proportional of each | ||
378 | // that is applied. This could be multiplied through the actual factors but it | ||
379 | // is sometimes easier to manipulate the factors and their mix separately. | ||
380 | public Vector3 FactorMix; | ||
381 | |||
382 | // Arbritrary factor range. | ||
383 | // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. | ||
384 | public float EfficiencyHigh = 0.4f; | ||
385 | public float EfficiencyLow = 4.0f; | ||
386 | |||
387 | // Running integration of the error | ||
388 | Vector3 RunningIntegration { get; set; } | ||
389 | |||
390 | public BSPIDVMotor(string useName) | ||
391 | : base(useName) | ||
392 | { | ||
393 | proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
394 | integralFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
395 | derivFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
396 | FactorMix = new Vector3(0.5f, 0.25f, 0.25f); | ||
397 | RunningIntegration = Vector3.Zero; | ||
398 | LastError = Vector3.Zero; | ||
399 | } | ||
400 | |||
401 | public override void Zero() | ||
402 | { | ||
403 | base.Zero(); | ||
404 | } | ||
405 | |||
406 | public override float Efficiency | ||
407 | { | ||
408 | get { return base.Efficiency; } | ||
409 | set | ||
410 | { | ||
411 | base.Efficiency = Util.Clamp(value, 0f, 1f); | ||
412 | |||
413 | // Compute factors based on efficiency. | ||
414 | // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. | ||
415 | // If efficiency is low (0f), use a factor value that overcorrects. | ||
416 | // TODO: might want to vary contribution of different factor depending on efficiency. | ||
417 | // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; | ||
418 | float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; | ||
419 | |||
420 | proportionFactor = new Vector3(factor, factor, factor); | ||
421 | integralFactor = new Vector3(factor, factor, factor); | ||
422 | derivFactor = new Vector3(factor, factor, factor); | ||
423 | |||
424 | MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | // Advance the PID computation on this error. | ||
429 | public override Vector3 StepError(float timeStep, Vector3 error) | ||
430 | { | ||
431 | if (!Enabled) return Vector3.Zero; | ||
432 | |||
433 | // Add up the error so we can integrate over the accumulated errors | ||
434 | RunningIntegration += error * timeStep; | ||
435 | |||
436 | // A simple derivitive is the rate of change from the last error. | ||
437 | Vector3 derivitive = (error - LastError) * timeStep; | ||
438 | |||
439 | // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) | ||
440 | Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X | ||
441 | + RunningIntegration / TimeScale * integralFactor * FactorMix.Y | ||
442 | + derivitive / TimeScale * derivFactor * FactorMix.Z | ||
443 | ; | ||
444 | |||
445 | MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}", | ||
446 | BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret); | ||
447 | |||
448 | return ret; | ||
449 | } | ||
450 | } | ||
451 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs new file mode 100755 index 0000000..6d46fe6 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs | |||
@@ -0,0 +1,927 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using System.Text; | ||
31 | |||
32 | using OpenSim.Region.Physics.Manager; | ||
33 | |||
34 | using OpenMetaverse; | ||
35 | using Nini.Config; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public static class BSParam | ||
40 | { | ||
41 | private static string LogHeader = "[BULLETSIM PARAMETERS]"; | ||
42 | |||
43 | // Tuning notes: | ||
44 | // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 | ||
45 | // Contact points can be added even if the distance is positive. The constraint solver can deal with | ||
46 | // contacts with positive distances as well as negative (penetration). Contact points are discarded | ||
47 | // if the distance exceeds a certain threshold. | ||
48 | // Bullet has a contact processing threshold and a contact breaking threshold. | ||
49 | // If the distance is larger than the contact breaking threshold, it will be removed after one frame. | ||
50 | // If the distance is larger than the contact processing threshold, the constraint solver will ignore it. | ||
51 | |||
52 | // This is separate/independent from the collision margin. The collision margin increases the object a bit | ||
53 | // to improve collision detection performance and accuracy. | ||
54 | // =================== | ||
55 | // From: | ||
56 | |||
57 | /// <summary> | ||
58 | /// Set whether physics is active or not. | ||
59 | /// </summary> | ||
60 | /// <remarks> | ||
61 | /// Can be enabled and disabled to start and stop physics. | ||
62 | /// </remarks> | ||
63 | public static bool Active { get; private set; } | ||
64 | |||
65 | public static bool UseSeparatePhysicsThread { get; private set; } | ||
66 | public static float PhysicsTimeStep { get; private set; } | ||
67 | |||
68 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
69 | public static float MeshLOD { get; private set; } | ||
70 | public static float MeshCircularLOD { get; private set; } | ||
71 | public static float MeshMegaPrimLOD { get; private set; } | ||
72 | public static float MeshMegaPrimThreshold { get; private set; } | ||
73 | public static float SculptLOD { get; private set; } | ||
74 | |||
75 | public static int CrossingFailuresBeforeOutOfBounds { get; private set; } | ||
76 | public static float UpdateVelocityChangeThreshold { get; private set; } | ||
77 | |||
78 | public static float MinimumObjectMass { get; private set; } | ||
79 | public static float MaximumObjectMass { get; private set; } | ||
80 | public static float MaxLinearVelocity { get; private set; } | ||
81 | public static float MaxLinearVelocitySquared { get; private set; } | ||
82 | public static float MaxAngularVelocity { get; private set; } | ||
83 | public static float MaxAngularVelocitySquared { get; private set; } | ||
84 | public static float MaxAddForceMagnitude { get; private set; } | ||
85 | public static float MaxAddForceMagnitudeSquared { get; private set; } | ||
86 | public static float DensityScaleFactor { get; private set; } | ||
87 | |||
88 | public static float LinearDamping { get; private set; } | ||
89 | public static float AngularDamping { get; private set; } | ||
90 | public static float DeactivationTime { get; private set; } | ||
91 | public static float LinearSleepingThreshold { get; private set; } | ||
92 | public static float AngularSleepingThreshold { get; private set; } | ||
93 | public static float CcdMotionThreshold { get; private set; } | ||
94 | public static float CcdSweptSphereRadius { get; private set; } | ||
95 | public static float ContactProcessingThreshold { get; private set; } | ||
96 | |||
97 | public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | ||
98 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | ||
99 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
100 | public static bool ShouldRemoveZeroWidthTriangles { get; private set; } | ||
101 | public static bool ShouldUseBulletHACD { get; set; } | ||
102 | public static bool ShouldUseSingleConvexHullForPrims { get; set; } | ||
103 | public static bool ShouldUseGImpactShapeForPrims { get; set; } | ||
104 | public static bool ShouldUseAssetHulls { get; set; } | ||
105 | |||
106 | public static float TerrainImplementation { get; set; } | ||
107 | public static int TerrainMeshMagnification { get; private set; } | ||
108 | public static float TerrainGroundPlane { get; private set; } | ||
109 | public static float TerrainFriction { get; private set; } | ||
110 | public static float TerrainHitFraction { get; private set; } | ||
111 | public static float TerrainRestitution { get; private set; } | ||
112 | public static float TerrainContactProcessingThreshold { get; private set; } | ||
113 | public static float TerrainCollisionMargin { get; private set; } | ||
114 | |||
115 | public static float DefaultFriction { get; private set; } | ||
116 | public static float DefaultDensity { get; private set; } | ||
117 | public static float DefaultRestitution { get; private set; } | ||
118 | public static float CollisionMargin { get; private set; } | ||
119 | public static float Gravity { get; private set; } | ||
120 | |||
121 | // Physics Engine operation | ||
122 | public static float MaxPersistantManifoldPoolSize { get; private set; } | ||
123 | public static float MaxCollisionAlgorithmPoolSize { get; private set; } | ||
124 | public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; } | ||
125 | public static bool ShouldForceUpdateAllAabbs { get; private set; } | ||
126 | public static bool ShouldRandomizeSolverOrder { get; private set; } | ||
127 | public static bool ShouldSplitSimulationIslands { get; private set; } | ||
128 | public static bool ShouldEnableFrictionCaching { get; private set; } | ||
129 | public static float NumberOfSolverIterations { get; private set; } | ||
130 | public static bool UseSingleSidedMeshes { get; private set; } | ||
131 | public static float GlobalContactBreakingThreshold { get; private set; } | ||
132 | public static float PhysicsUnmanLoggingFrames { get; private set; } | ||
133 | |||
134 | // Avatar parameters | ||
135 | public static bool AvatarToAvatarCollisionsByDefault { get; private set; } | ||
136 | public static float AvatarFriction { get; private set; } | ||
137 | public static float AvatarStandingFriction { get; private set; } | ||
138 | public static float AvatarAlwaysRunFactor { get; private set; } | ||
139 | public static float AvatarDensity { get; private set; } | ||
140 | public static float AvatarRestitution { get; private set; } | ||
141 | public static int AvatarShape { get; private set; } | ||
142 | public static float AvatarCapsuleWidth { get; private set; } | ||
143 | public static float AvatarCapsuleDepth { get; private set; } | ||
144 | public static float AvatarCapsuleHeight { get; private set; } | ||
145 | public static float AvatarHeightLowFudge { get; private set; } | ||
146 | public static float AvatarHeightMidFudge { get; private set; } | ||
147 | public static float AvatarHeightHighFudge { get; private set; } | ||
148 | public static float AvatarFlyingGroundMargin { get; private set; } | ||
149 | public static float AvatarFlyingGroundUpForce { get; private set; } | ||
150 | public static float AvatarTerminalVelocity { get; private set; } | ||
151 | public static float AvatarContactProcessingThreshold { get; private set; } | ||
152 | public static float AvatarStopZeroThreshold { get; private set; } | ||
153 | public static int AvatarJumpFrames { get; private set; } | ||
154 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } | ||
155 | public static float AvatarStepHeight { get; private set; } | ||
156 | public static float AvatarStepAngle { get; private set; } | ||
157 | public static float AvatarStepGroundFudge { get; private set; } | ||
158 | public static float AvatarStepApproachFactor { get; private set; } | ||
159 | public static float AvatarStepForceFactor { get; private set; } | ||
160 | public static float AvatarStepUpCorrectionFactor { get; private set; } | ||
161 | public static int AvatarStepSmoothingSteps { get; private set; } | ||
162 | |||
163 | // Vehicle parameters | ||
164 | public static float VehicleMaxLinearVelocity { get; private set; } | ||
165 | public static float VehicleMaxLinearVelocitySquared { get; private set; } | ||
166 | public static float VehicleMinLinearVelocity { get; private set; } | ||
167 | public static float VehicleMinLinearVelocitySquared { get; private set; } | ||
168 | public static float VehicleMaxAngularVelocity { get; private set; } | ||
169 | public static float VehicleMaxAngularVelocitySq { get; private set; } | ||
170 | public static float VehicleAngularDamping { get; private set; } | ||
171 | public static float VehicleFriction { get; private set; } | ||
172 | public static float VehicleRestitution { get; private set; } | ||
173 | public static Vector3 VehicleLinearFactor { get; private set; } | ||
174 | public static Vector3 VehicleAngularFactor { get; private set; } | ||
175 | public static Vector3 VehicleInertiaFactor { get; private set; } | ||
176 | public static float VehicleGroundGravityFudge { get; private set; } | ||
177 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } | ||
178 | public static bool VehicleEnableLinearDeflection { get; private set; } | ||
179 | public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; } | ||
180 | public static bool VehicleEnableAngularVerticalAttraction { get; private set; } | ||
181 | public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; } | ||
182 | public static bool VehicleEnableAngularDeflection { get; private set; } | ||
183 | public static bool VehicleEnableAngularBanking { get; private set; } | ||
184 | |||
185 | // Convex Hulls | ||
186 | // Parameters for convex hull routine that ships with Bullet | ||
187 | public static int CSHullMaxDepthSplit { get; private set; } | ||
188 | public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; } | ||
189 | public static float CSHullConcavityThresholdPercent { get; private set; } | ||
190 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } | ||
191 | public static int CSHullMaxVertices { get; private set; } | ||
192 | public static float CSHullMaxSkinWidth { get; private set; } | ||
193 | public static float BHullMaxVerticesPerHull { get; private set; } // 100 | ||
194 | public static float BHullMinClusters { get; private set; } // 2 | ||
195 | public static float BHullCompacityWeight { get; private set; } // 0.1 | ||
196 | public static float BHullVolumeWeight { get; private set; } // 0.0 | ||
197 | public static float BHullConcavity { get; private set; } // 100 | ||
198 | public static bool BHullAddExtraDistPoints { get; private set; } // false | ||
199 | public static bool BHullAddNeighboursDistPoints { get; private set; } // false | ||
200 | public static bool BHullAddFacesPoints { get; private set; } // false | ||
201 | public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false | ||
202 | public static float WhichHACD { get; private set; } // zero if Bullet HACD, non-zero says VHACD | ||
203 | // Parameters for VHACD 2.0: http://code.google.com/p/v-hacd | ||
204 | // To enable, set both ShouldUseBulletHACD=true and WhichHACD=1 | ||
205 | // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html | ||
206 | public static float VHACDresolution { get; private set; } // 100,000 max number of voxels generated during voxelization stage | ||
207 | public static float VHACDdepth { get; private set; } // 20 max number of clipping stages | ||
208 | public static float VHACDconcavity { get; private set; } // 0.0025 maximum concavity | ||
209 | public static float VHACDplaneDownsampling { get; private set; } // 4 granularity of search for best clipping plane | ||
210 | public static float VHACDconvexHullDownsampling { get; private set; } // 4 precision of hull gen process | ||
211 | public static float VHACDalpha { get; private set; } // 0.05 bias toward clipping along symmetry planes | ||
212 | public static float VHACDbeta { get; private set; } // 0.05 bias toward clipping along revolution axis | ||
213 | public static float VHACDgamma { get; private set; } // 0.00125 max concavity when merging | ||
214 | public static float VHACDpca { get; private set; } // 0 on/off normalizing mesh before decomp | ||
215 | public static float VHACDmode { get; private set; } // 0 0:voxel based, 1: tetrahedron based | ||
216 | public static float VHACDmaxNumVerticesPerCH { get; private set; } // 64 max triangles per convex hull | ||
217 | public static float VHACDminVolumePerCH { get; private set; } // 0.0001 sampling of generated convex hulls | ||
218 | |||
219 | // Linkset implementation parameters | ||
220 | public static float LinksetImplementation { get; private set; } | ||
221 | public static bool LinksetOffsetCenterOfMass { get; private set; } | ||
222 | public static bool LinkConstraintUseFrameOffset { get; private set; } | ||
223 | public static bool LinkConstraintEnableTransMotor { get; private set; } | ||
224 | public static float LinkConstraintTransMotorMaxVel { get; private set; } | ||
225 | public static float LinkConstraintTransMotorMaxForce { get; private set; } | ||
226 | public static float LinkConstraintERP { get; private set; } | ||
227 | public static float LinkConstraintCFM { get; private set; } | ||
228 | public static float LinkConstraintSolverIterations { get; private set; } | ||
229 | |||
230 | public static float PID_D { get; private set; } // derivative | ||
231 | public static float PID_P { get; private set; } // proportional | ||
232 | |||
233 | // Various constants that come from that other virtual world that shall not be named. | ||
234 | public const float MinGravityZ = -1f; | ||
235 | public const float MaxGravityZ = 28f; | ||
236 | public const float MinFriction = 0f; | ||
237 | public const float MaxFriction = 255f; | ||
238 | public const float MinDensity = 0.01f; | ||
239 | public const float MaxDensity = 22587f; | ||
240 | public const float MinRestitution = 0f; | ||
241 | public const float MaxRestitution = 1f; | ||
242 | |||
243 | // ===================================================================================== | ||
244 | // ===================================================================================== | ||
245 | |||
246 | // Base parameter definition that gets and sets parameter values via a string | ||
247 | public abstract class ParameterDefnBase | ||
248 | { | ||
249 | public string name; // string name of the parameter | ||
250 | public string desc; // a short description of what the parameter means | ||
251 | public ParameterDefnBase(string pName, string pDesc) | ||
252 | { | ||
253 | name = pName; | ||
254 | desc = pDesc; | ||
255 | } | ||
256 | // Set the parameter value to the default | ||
257 | public abstract void AssignDefault(BSScene s); | ||
258 | // Get the value as a string | ||
259 | public abstract string GetValue(BSScene s); | ||
260 | // Set the value to this string value | ||
261 | public abstract void SetValue(BSScene s, string valAsString); | ||
262 | // set the value on a particular object (usually sets in physics engine) | ||
263 | public abstract void SetOnObject(BSScene s, BSPhysObject obj); | ||
264 | public abstract bool HasSetOnObject { get; } | ||
265 | } | ||
266 | |||
267 | // Specific parameter definition for a parameter of a specific type. | ||
268 | public delegate T PGetValue<T>(BSScene s); | ||
269 | public delegate void PSetValue<T>(BSScene s, T val); | ||
270 | public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj); | ||
271 | public sealed class ParameterDefn<T> : ParameterDefnBase | ||
272 | { | ||
273 | private T defaultValue; | ||
274 | private PSetValue<T> setter; | ||
275 | private PGetValue<T> getter; | ||
276 | private PSetOnObject<T> objectSet; | ||
277 | public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter) | ||
278 | : base(pName, pDesc) | ||
279 | { | ||
280 | defaultValue = pDefault; | ||
281 | setter = pSetter; | ||
282 | getter = pGetter; | ||
283 | objectSet = null; | ||
284 | } | ||
285 | public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter, PSetOnObject<T> pObjSetter) | ||
286 | : base(pName, pDesc) | ||
287 | { | ||
288 | defaultValue = pDefault; | ||
289 | setter = pSetter; | ||
290 | getter = pGetter; | ||
291 | objectSet = pObjSetter; | ||
292 | } | ||
293 | // Simple parameter variable where property name is the same as the INI file name | ||
294 | // and the value is only a simple get and set. | ||
295 | public ParameterDefn(string pName, string pDesc, T pDefault) | ||
296 | : base(pName, pDesc) | ||
297 | { | ||
298 | defaultValue = pDefault; | ||
299 | setter = (s, v) => { SetValueByName(s, name, v); }; | ||
300 | getter = (s) => { return GetValueByName(s, name); }; | ||
301 | objectSet = null; | ||
302 | } | ||
303 | // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. | ||
304 | private void SetValueByName(BSScene s, string pName, T val) | ||
305 | { | ||
306 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
307 | if (prop == null) | ||
308 | { | ||
309 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
310 | s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); | ||
311 | } | ||
312 | else | ||
313 | { | ||
314 | prop.SetValue(null, val, null); | ||
315 | } | ||
316 | } | ||
317 | // Use reflection to find the property named 'pName' in BSParam and return the value in same. | ||
318 | private T GetValueByName(BSScene s, string pName) | ||
319 | { | ||
320 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
321 | if (prop == null) | ||
322 | { | ||
323 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
324 | s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); | ||
325 | } | ||
326 | return (T)prop.GetValue(null, null); | ||
327 | } | ||
328 | public override void AssignDefault(BSScene s) | ||
329 | { | ||
330 | setter(s, defaultValue); | ||
331 | } | ||
332 | public override string GetValue(BSScene s) | ||
333 | { | ||
334 | return getter(s).ToString(); | ||
335 | } | ||
336 | public override void SetValue(BSScene s, string valAsString) | ||
337 | { | ||
338 | // Get the generic type of the setter | ||
339 | Type genericType = setter.GetType().GetGenericArguments()[0]; | ||
340 | // Find the 'Parse' method on that type | ||
341 | System.Reflection.MethodInfo parser = null; | ||
342 | try | ||
343 | { | ||
344 | parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } ); | ||
345 | } | ||
346 | catch (Exception e) | ||
347 | { | ||
348 | s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e); | ||
349 | parser = null; | ||
350 | } | ||
351 | if (parser != null) | ||
352 | { | ||
353 | // Parse the input string | ||
354 | try | ||
355 | { | ||
356 | T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); | ||
357 | // Store the parsed value | ||
358 | setter(s, setValue); | ||
359 | // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); | ||
360 | } | ||
361 | catch | ||
362 | { | ||
363 | s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType); | ||
364 | } | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType); | ||
369 | } | ||
370 | } | ||
371 | public override bool HasSetOnObject | ||
372 | { | ||
373 | get { return objectSet != null; } | ||
374 | } | ||
375 | public override void SetOnObject(BSScene s, BSPhysObject obj) | ||
376 | { | ||
377 | if (objectSet != null) | ||
378 | objectSet(s, obj); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | // List of all of the externally visible parameters. | ||
383 | // For each parameter, this table maps a text name to getter and setters. | ||
384 | // To add a new externally referencable/settable parameter, add the paramter storage | ||
385 | // location somewhere in the program and make an entry in this table with the | ||
386 | // getters and setters. | ||
387 | // It is easiest to find an existing definition and copy it. | ||
388 | // | ||
389 | // A ParameterDefn<T>() takes the following parameters: | ||
390 | // -- the text name of the parameter. This is used for console input and ini file. | ||
391 | // -- a short text description of the parameter. This shows up in the console listing. | ||
392 | // -- a default value | ||
393 | // -- a delegate for getting the value | ||
394 | // -- a delegate for setting the value | ||
395 | // -- an optional delegate to update the value in the world. Most often used to | ||
396 | // push the new value to an in-world object. | ||
397 | // | ||
398 | // The single letter parameters for the delegates are: | ||
399 | // s = BSScene | ||
400 | // o = BSPhysObject | ||
401 | // v = value (appropriate type) | ||
402 | private static ParameterDefnBase[] ParameterDefinitions = | ||
403 | { | ||
404 | new ParameterDefn<bool>("Active", "If 'true', false then physics is not active", | ||
405 | false ), | ||
406 | new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", | ||
407 | false ), | ||
408 | new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", | ||
409 | 0.089f ), | ||
410 | |||
411 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", | ||
412 | true, | ||
413 | (s) => { return ShouldMeshSculptedPrim; }, | ||
414 | (s,v) => { ShouldMeshSculptedPrim = v; } ), | ||
415 | new ParameterDefn<bool>("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | ||
416 | false, | ||
417 | (s) => { return ShouldForceSimplePrimMeshing; }, | ||
418 | (s,v) => { ShouldForceSimplePrimMeshing = v; } ), | ||
419 | new ParameterDefn<bool>("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
420 | true, | ||
421 | (s) => { return ShouldUseHullsForPhysicalObjects; }, | ||
422 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), | ||
423 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", | ||
424 | true ), | ||
425 | new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", | ||
426 | false ), | ||
427 | new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", | ||
428 | true ), | ||
429 | new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", | ||
430 | false ), | ||
431 | new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", | ||
432 | true ), | ||
433 | |||
434 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", | ||
435 | 5 ), | ||
436 | new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", | ||
437 | 0.1f ), | ||
438 | |||
439 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||
440 | 32f, | ||
441 | (s) => { return MeshLOD; }, | ||
442 | (s,v) => { MeshLOD = v; } ), | ||
443 | new ParameterDefn<float>("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes", | ||
444 | 32f, | ||
445 | (s) => { return MeshCircularLOD; }, | ||
446 | (s,v) => { MeshCircularLOD = v; } ), | ||
447 | new ParameterDefn<float>("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
448 | 10f, | ||
449 | (s) => { return MeshMegaPrimThreshold; }, | ||
450 | (s,v) => { MeshMegaPrimThreshold = v; } ), | ||
451 | new ParameterDefn<float>("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | ||
452 | 32f, | ||
453 | (s) => { return MeshMegaPrimLOD; }, | ||
454 | (s,v) => { MeshMegaPrimLOD = v; } ), | ||
455 | new ParameterDefn<float>("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
456 | 32f, | ||
457 | (s) => { return SculptLOD; }, | ||
458 | (s,v) => { SculptLOD = v; } ), | ||
459 | |||
460 | new ParameterDefn<int>("MaxSubStep", "In simulation step, maximum number of substeps", | ||
461 | 10, | ||
462 | (s) => { return s.m_maxSubSteps; }, | ||
463 | (s,v) => { s.m_maxSubSteps = (int)v; } ), | ||
464 | new ParameterDefn<float>("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||
465 | 1f / 60f, | ||
466 | (s) => { return s.m_fixedTimeStep; }, | ||
467 | (s,v) => { s.m_fixedTimeStep = v; } ), | ||
468 | new ParameterDefn<float>("NominalFrameRate", "The base frame rate we claim", | ||
469 | 55f, | ||
470 | (s) => { return s.NominalFrameRate; }, | ||
471 | (s,v) => { s.NominalFrameRate = (int)v; } ), | ||
472 | new ParameterDefn<int>("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | ||
473 | 2048, | ||
474 | (s) => { return s.m_maxCollisionsPerFrame; }, | ||
475 | (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | ||
476 | new ParameterDefn<int>("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | ||
477 | 8000, | ||
478 | (s) => { return s.m_maxUpdatesPerFrame; }, | ||
479 | (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||
480 | |||
481 | new ParameterDefn<float>("MinObjectMass", "Minimum object mass (0.0001)", | ||
482 | 0.0001f, | ||
483 | (s) => { return MinimumObjectMass; }, | ||
484 | (s,v) => { MinimumObjectMass = v; } ), | ||
485 | new ParameterDefn<float>("MaxObjectMass", "Maximum object mass (10000.01)", | ||
486 | 10000.01f, | ||
487 | (s) => { return MaximumObjectMass; }, | ||
488 | (s,v) => { MaximumObjectMass = v; } ), | ||
489 | new ParameterDefn<float>("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object", | ||
490 | 1000.0f, | ||
491 | (s) => { return MaxLinearVelocity; }, | ||
492 | (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ), | ||
493 | new ParameterDefn<float>("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object", | ||
494 | 1000.0f, | ||
495 | (s) => { return MaxAngularVelocity; }, | ||
496 | (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ), | ||
497 | // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject | ||
498 | new ParameterDefn<float>("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)", | ||
499 | 20000.0f, | ||
500 | (s) => { return MaxAddForceMagnitude; }, | ||
501 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), | ||
502 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. | ||
503 | // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well | ||
504 | new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", | ||
505 | 0.01f ), | ||
506 | |||
507 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", | ||
508 | 2200f ), | ||
509 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", | ||
510 | 900f ), | ||
511 | |||
512 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", | ||
513 | 0.2f, | ||
514 | (s) => { return DefaultFriction; }, | ||
515 | (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), | ||
516 | // For historical reasons, the viewer and simulator multiply the density by 100 | ||
517 | new ParameterDefn<float>("DefaultDensity", "Density for new objects" , | ||
518 | 1000.0006836f, // Aluminum g/cm3 * 100 | ||
519 | (s) => { return DefaultDensity; }, | ||
520 | (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), | ||
521 | new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" , | ||
522 | 0f, | ||
523 | (s) => { return DefaultRestitution; }, | ||
524 | (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ), | ||
525 | new ParameterDefn<float>("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||
526 | 0.04f, | ||
527 | (s) => { return CollisionMargin; }, | ||
528 | (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ), | ||
529 | new ParameterDefn<float>("Gravity", "Vertical force of gravity (negative means down)", | ||
530 | -9.80665f, | ||
531 | (s) => { return Gravity; }, | ||
532 | (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; }, | ||
533 | (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ), | ||
534 | |||
535 | |||
536 | new ParameterDefn<float>("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | ||
537 | 0f, | ||
538 | (s) => { return LinearDamping; }, | ||
539 | (s,v) => { LinearDamping = v; }, | ||
540 | (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), | ||
541 | new ParameterDefn<float>("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | ||
542 | 0f, | ||
543 | (s) => { return AngularDamping; }, | ||
544 | (s,v) => { AngularDamping = v; }, | ||
545 | (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), | ||
546 | new ParameterDefn<float>("DeactivationTime", "Seconds before considering an object potentially static", | ||
547 | 0.2f, | ||
548 | (s) => { return DeactivationTime; }, | ||
549 | (s,v) => { DeactivationTime = v; }, | ||
550 | (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ), | ||
551 | new ParameterDefn<float>("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | ||
552 | 0.8f, | ||
553 | (s) => { return LinearSleepingThreshold; }, | ||
554 | (s,v) => { LinearSleepingThreshold = v;}, | ||
555 | (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), | ||
556 | new ParameterDefn<float>("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | ||
557 | 1.0f, | ||
558 | (s) => { return AngularSleepingThreshold; }, | ||
559 | (s,v) => { AngularSleepingThreshold = v;}, | ||
560 | (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), | ||
561 | new ParameterDefn<float>("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | ||
562 | 0.0f, // set to zero to disable | ||
563 | (s) => { return CcdMotionThreshold; }, | ||
564 | (s,v) => { CcdMotionThreshold = v;}, | ||
565 | (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ), | ||
566 | new ParameterDefn<float>("CcdSweptSphereRadius", "Continuious collision detection test radius" , | ||
567 | 0.2f, | ||
568 | (s) => { return CcdSweptSphereRadius; }, | ||
569 | (s,v) => { CcdSweptSphereRadius = v;}, | ||
570 | (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ), | ||
571 | new ParameterDefn<float>("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" , | ||
572 | 0.0f, | ||
573 | (s) => { return ContactProcessingThreshold; }, | ||
574 | (s,v) => { ContactProcessingThreshold = v;}, | ||
575 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), | ||
576 | |||
577 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||
578 | (float)BSTerrainPhys.TerrainImplementation.Heightmap ), | ||
579 | new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , | ||
580 | 2 ), | ||
581 | new ParameterDefn<float>("TerrainGroundPlane", "Altitude of ground plane used to keep things from falling to infinity" , | ||
582 | -500.0f ), | ||
583 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , | ||
584 | 0.3f ), | ||
585 | new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , | ||
586 | 0.8f ), | ||
587 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , | ||
588 | 0f ), | ||
589 | new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , | ||
590 | 0.0f ), | ||
591 | new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
592 | 0.04f ), | ||
593 | |||
594 | new ParameterDefn<bool>("AvatarToAvatarCollisionsByDefault", "Should avatars collide with other avatars by default?", | ||
595 | true), | ||
596 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||
597 | 0.2f ), | ||
598 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
599 | 0.95f ), | ||
600 | new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", | ||
601 | 1.3f ), | ||
602 | // For historical reasons, density is reported * 100 | ||
603 | new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.", | ||
604 | 3500f) , // 3.5 * 100 | ||
605 | new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
606 | 0f ), | ||
607 | new ParameterDefn<int>("AvatarShape", "Code for avatar physical shape: 0:capsule, 1:cube, 2:ovoid, 2:mesh", | ||
608 | BSShapeCollection.AvatarShapeCube ) , | ||
609 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||
610 | 0.6f ) , | ||
611 | new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
612 | 0.45f ), | ||
613 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", | ||
614 | 1.5f ), | ||
615 | new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", | ||
616 | 0f ), | ||
617 | new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", | ||
618 | 0f ), | ||
619 | new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", | ||
620 | 0f ), | ||
621 | new ParameterDefn<float>("AvatarFlyingGroundMargin", "Meters avatar is kept above the ground when flying", | ||
622 | 5f ), | ||
623 | new ParameterDefn<float>("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin", | ||
624 | 2.0f ), | ||
625 | new ParameterDefn<float>("AvatarTerminalVelocity", "Terminal Velocity of falling avatar", | ||
626 | -54.0f ), | ||
627 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||
628 | 0.1f ), | ||
629 | new ParameterDefn<float>("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped", | ||
630 | 0.1f ), | ||
631 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", | ||
632 | 1.0f ), | ||
633 | new ParameterDefn<int>("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", | ||
634 | 4 ), | ||
635 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", | ||
636 | 0.999f ) , | ||
637 | new ParameterDefn<float>("AvatarStepAngle", "The angle (in radians) for a vertical surface to be considered a step", | ||
638 | 0.3f ) , | ||
639 | new ParameterDefn<float>("AvatarStepGroundFudge", "Fudge factor subtracted from avatar base when comparing collision height", | ||
640 | 0.1f ) , | ||
641 | new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", | ||
642 | 2f ), | ||
643 | new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", | ||
644 | 0f ), | ||
645 | new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", | ||
646 | 0.8f ), | ||
647 | new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", | ||
648 | 1 ), | ||
649 | |||
650 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", | ||
651 | 1000.0f, | ||
652 | (s) => { return (float)VehicleMaxLinearVelocity; }, | ||
653 | (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ), | ||
654 | new ParameterDefn<float>("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", | ||
655 | 0.001f, | ||
656 | (s) => { return (float)VehicleMinLinearVelocity; }, | ||
657 | (s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ), | ||
658 | new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle", | ||
659 | 12.0f, | ||
660 | (s) => { return (float)VehicleMaxAngularVelocity; }, | ||
661 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), | ||
662 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
663 | 0.0f ), | ||
664 | new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", | ||
665 | new Vector3(1f, 1f, 1f) ), | ||
666 | new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", | ||
667 | new Vector3(1f, 1f, 1f) ), | ||
668 | new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)", | ||
669 | new Vector3(1f, 1f, 1f) ), | ||
670 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", | ||
671 | 0.0f ), | ||
672 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", | ||
673 | 0.0f ), | ||
674 | new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", | ||
675 | 0.2f ), | ||
676 | new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", | ||
677 | 60.0f ), | ||
678 | new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", | ||
679 | true ), | ||
680 | new ParameterDefn<bool>("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles", | ||
681 | true ), | ||
682 | new ParameterDefn<bool>("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect", | ||
683 | true ), | ||
684 | new ParameterDefn<int>("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.", | ||
685 | 0 ), | ||
686 | new ParameterDefn<bool>("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect", | ||
687 | true ), | ||
688 | new ParameterDefn<bool>("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect", | ||
689 | true ), | ||
690 | |||
691 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||
692 | 0f, | ||
693 | (s) => { return MaxPersistantManifoldPoolSize; }, | ||
694 | (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), | ||
695 | new ParameterDefn<float>("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | ||
696 | 0f, | ||
697 | (s) => { return MaxCollisionAlgorithmPoolSize; }, | ||
698 | (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), | ||
699 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||
700 | false, | ||
701 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, | ||
702 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; | ||
703 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), | ||
704 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||
705 | false, | ||
706 | (s) => { return ShouldForceUpdateAllAabbs; }, | ||
707 | (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ), | ||
708 | new ParameterDefn<bool>("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||
709 | true, | ||
710 | (s) => { return ShouldRandomizeSolverOrder; }, | ||
711 | (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ), | ||
712 | new ParameterDefn<bool>("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||
713 | true, | ||
714 | (s) => { return ShouldSplitSimulationIslands; }, | ||
715 | (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ), | ||
716 | new ParameterDefn<bool>("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||
717 | true, | ||
718 | (s) => { return ShouldEnableFrictionCaching; }, | ||
719 | (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ), | ||
720 | new ParameterDefn<float>("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||
721 | 0f, // zero says use Bullet default | ||
722 | (s) => { return NumberOfSolverIterations; }, | ||
723 | (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ), | ||
724 | new ParameterDefn<bool>("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.", | ||
725 | true, | ||
726 | (s) => { return UseSingleSidedMeshes; }, | ||
727 | (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ), | ||
728 | new ParameterDefn<float>("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))", | ||
729 | 0f, | ||
730 | (s) => { return GlobalContactBreakingThreshold; }, | ||
731 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), | ||
732 | new ParameterDefn<float>("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics", | ||
733 | 0f, | ||
734 | (s) => { return PhysicsUnmanLoggingFrames; }, | ||
735 | (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ), | ||
736 | |||
737 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", | ||
738 | 7 ), | ||
739 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", | ||
740 | 2 ), | ||
741 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", | ||
742 | 5f ), | ||
743 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", | ||
744 | 5f ), | ||
745 | new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", | ||
746 | 32 ), | ||
747 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", | ||
748 | 0f ), | ||
749 | |||
750 | new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", | ||
751 | 200f ), | ||
752 | new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", | ||
753 | 10f ), | ||
754 | new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", | ||
755 | 20f ), | ||
756 | new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", | ||
757 | 0.1f ), | ||
758 | new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", | ||
759 | 10f ), | ||
760 | new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", | ||
761 | true ), | ||
762 | new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", | ||
763 | true ), | ||
764 | new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", | ||
765 | true ), | ||
766 | new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", | ||
767 | false ), | ||
768 | |||
769 | new ParameterDefn<float>("WhichHACD", "zero if Bullet HACD, non-zero says VHACD", | ||
770 | 0f ), | ||
771 | new ParameterDefn<float>("VHACDresolution", "max number of voxels generated during voxelization stage", | ||
772 | 100000f ), | ||
773 | new ParameterDefn<float>("VHACDdepth", "max number of clipping stages", | ||
774 | 20f ), | ||
775 | new ParameterDefn<float>("VHACDconcavity", "maximum concavity", | ||
776 | 0.0025f ), | ||
777 | new ParameterDefn<float>("VHACDplaneDownsampling", "granularity of search for best clipping plane", | ||
778 | 4f ), | ||
779 | new ParameterDefn<float>("VHACDconvexHullDownsampling", "precision of hull gen process", | ||
780 | 4f ), | ||
781 | new ParameterDefn<float>("VHACDalpha", "bias toward clipping along symmetry planes", | ||
782 | 0.05f ), | ||
783 | new ParameterDefn<float>("VHACDbeta", "bias toward clipping along revolution axis", | ||
784 | 0.05f ), | ||
785 | new ParameterDefn<float>("VHACDgamma", "max concavity when merging", | ||
786 | 0.00125f ), | ||
787 | new ParameterDefn<float>("VHACDpca", "on/off normalizing mesh before decomp", | ||
788 | 0f ), | ||
789 | new ParameterDefn<float>("VHACDmode", "0:voxel based, 1: tetrahedron based", | ||
790 | 0f ), | ||
791 | new ParameterDefn<float>("VHACDmaxNumVerticesPerCH", "max triangles per convex hull", | ||
792 | 64f ), | ||
793 | new ParameterDefn<float>("VHACDminVolumePerCH", "sampling of generated convex hulls", | ||
794 | 0.0001f ), | ||
795 | |||
796 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
797 | (float)BSLinkset.LinksetImplementation.Compound ), | ||
798 | new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same", | ||
799 | true ), | ||
800 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
801 | false ), | ||
802 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
803 | true ), | ||
804 | new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
805 | 5.0f ), | ||
806 | new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
807 | 0.1f ), | ||
808 | new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
809 | 0.1f ), | ||
810 | new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
811 | 0.1f ), | ||
812 | new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
813 | 40 ), | ||
814 | |||
815 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", | ||
816 | 0, | ||
817 | (s) => { return s.PhysicsMetricDumpFrames; }, | ||
818 | (s,v) => { s.PhysicsMetricDumpFrames = v; } ), | ||
819 | new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", | ||
820 | 0f, | ||
821 | (s) => { return 0f; }, | ||
822 | (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ), | ||
823 | new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver", | ||
824 | 0f, | ||
825 | (s) => { return 0f; }, | ||
826 | (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ), | ||
827 | }; | ||
828 | |||
829 | // Convert a boolean to our numeric true and false values | ||
830 | public static float NumericBool(bool b) | ||
831 | { | ||
832 | return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); | ||
833 | } | ||
834 | |||
835 | // Convert numeric true and false values to a boolean | ||
836 | public static bool BoolNumeric(float b) | ||
837 | { | ||
838 | return (b == ConfigurationParameters.numericTrue ? true : false); | ||
839 | } | ||
840 | |||
841 | // Search through the parameter definitions and return the matching | ||
842 | // ParameterDefn structure. | ||
843 | // Case does not matter as names are compared after converting to lower case. | ||
844 | // Returns 'false' if the parameter is not found. | ||
845 | internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn) | ||
846 | { | ||
847 | bool ret = false; | ||
848 | ParameterDefnBase foundDefn = null; | ||
849 | string pName = paramName.ToLower(); | ||
850 | |||
851 | foreach (ParameterDefnBase parm in ParameterDefinitions) | ||
852 | { | ||
853 | if (pName == parm.name.ToLower()) | ||
854 | { | ||
855 | foundDefn = parm; | ||
856 | ret = true; | ||
857 | break; | ||
858 | } | ||
859 | } | ||
860 | defn = foundDefn; | ||
861 | return ret; | ||
862 | } | ||
863 | |||
864 | // Pass through the settable parameters and set the default values | ||
865 | internal static void SetParameterDefaultValues(BSScene physicsScene) | ||
866 | { | ||
867 | foreach (ParameterDefnBase parm in ParameterDefinitions) | ||
868 | { | ||
869 | parm.AssignDefault(physicsScene); | ||
870 | } | ||
871 | } | ||
872 | |||
873 | // Get user set values out of the ini file. | ||
874 | internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) | ||
875 | { | ||
876 | foreach (ParameterDefnBase parm in ParameterDefinitions) | ||
877 | { | ||
878 | parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene))); | ||
879 | } | ||
880 | } | ||
881 | |||
882 | internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | ||
883 | |||
884 | // This creates an array in the correct format for returning the list of | ||
885 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
886 | internal static void BuildParameterTable() | ||
887 | { | ||
888 | if (SettableParameters.Length < ParameterDefinitions.Length) | ||
889 | { | ||
890 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | ||
891 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | ||
892 | { | ||
893 | ParameterDefnBase pd = ParameterDefinitions[ii]; | ||
894 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | ||
895 | } | ||
896 | |||
897 | // make the list alphabetical for ease of finding anything | ||
898 | entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); }); | ||
899 | |||
900 | SettableParameters = entries.ToArray(); | ||
901 | } | ||
902 | } | ||
903 | |||
904 | // ===================================================================== | ||
905 | // ===================================================================== | ||
906 | // There are parameters that, when set, cause things to happen in the physics engine. | ||
907 | // This causes the broadphase collision cache to be cleared. | ||
908 | private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime) | ||
909 | { | ||
910 | BSScene physScene = pPhysScene; | ||
911 | physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate() | ||
912 | { | ||
913 | physScene.PE.ResetBroadphasePool(physScene.World); | ||
914 | }); | ||
915 | } | ||
916 | |||
917 | // This causes the constraint solver cache to be cleared and reset. | ||
918 | private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) | ||
919 | { | ||
920 | BSScene physScene = pPhysScene; | ||
921 | physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate() | ||
922 | { | ||
923 | physScene.PE.ResetConstraintSolver(physScene.World); | ||
924 | }); | ||
925 | } | ||
926 | } | ||
927 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs new file mode 100755 index 0000000..90da7a6 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs | |||
@@ -0,0 +1,620 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | /* | ||
38 | * Class to wrap all objects. | ||
39 | * The rest of BulletSim doesn't need to keep checking for avatars or prims | ||
40 | * unless the difference is significant. | ||
41 | * | ||
42 | * Variables in the physicsl objects are in three forms: | ||
43 | * VariableName: used by the simulator and performs taint operations, etc | ||
44 | * RawVariableName: direct reference to the BulletSim storage for the variable value | ||
45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. | ||
46 | * The last one should only be referenced in taint-time. | ||
47 | */ | ||
48 | |||
49 | /* | ||
50 | * As of 20121221, the following are the call sequences (going down) for different script physical functions: | ||
51 | * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce | ||
52 | * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce | ||
53 | * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse | ||
54 | * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v | ||
55 | * BS.ApplyCentralForce BS.ApplyTorque | ||
56 | */ | ||
57 | |||
58 | // Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. | ||
59 | public enum UpdatedProperties : uint | ||
60 | { | ||
61 | Position = 1 << 0, | ||
62 | Orientation = 1 << 1, | ||
63 | Velocity = 1 << 2, | ||
64 | Acceleration = 1 << 3, | ||
65 | RotationalVelocity = 1 << 4, | ||
66 | EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity, | ||
67 | } | ||
68 | public abstract class BSPhysObject : PhysicsActor | ||
69 | { | ||
70 | protected BSPhysObject() | ||
71 | { | ||
72 | } | ||
73 | protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) | ||
74 | { | ||
75 | IsInitialized = false; | ||
76 | |||
77 | PhysScene = parentScene; | ||
78 | LocalID = localID; | ||
79 | PhysObjectName = name; | ||
80 | Name = name; // PhysicsActor also has the name of the object. Someday consolidate. | ||
81 | TypeName = typeName; | ||
82 | |||
83 | // Oddity if object is destroyed and recreated very quickly it could still have the old body. | ||
84 | if (!PhysBody.HasPhysicalBody) | ||
85 | PhysBody = new BulletBody(localID); | ||
86 | |||
87 | // Clean out anything that might be in the physical actor list. | ||
88 | // Again, a workaround for destroying and recreating an object very quickly. | ||
89 | PhysicalActors.Dispose(); | ||
90 | |||
91 | UserSetCenterOfMassDisplacement = null; | ||
92 | |||
93 | PrimAssetState = PrimAssetCondition.Unknown; | ||
94 | |||
95 | // Initialize variables kept in base. | ||
96 | // Beware that these cause taints to be queued whch can cause race conditions on startup. | ||
97 | GravModifier = 1.0f; | ||
98 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); | ||
99 | HoverActive = false; | ||
100 | |||
101 | // Default material type. Also sets Friction, Restitution and Density. | ||
102 | SetMaterial((int)MaterialAttributes.Material.Wood); | ||
103 | |||
104 | CollisionsLastTickStep = -1; | ||
105 | |||
106 | SubscribedEventsMs = 0; | ||
107 | // Crazy values that will never be true | ||
108 | CollidingStep = BSScene.NotASimulationStep; | ||
109 | CollidingGroundStep = BSScene.NotASimulationStep; | ||
110 | CollisionAccumulation = BSScene.NotASimulationStep; | ||
111 | ColliderIsMoving = false; | ||
112 | CollisionScore = 0; | ||
113 | |||
114 | // All axis free. | ||
115 | LockedLinearAxis = LockedAxisFree; | ||
116 | LockedAngularAxis = LockedAxisFree; | ||
117 | } | ||
118 | |||
119 | // Tell the object to clean up. | ||
120 | public virtual void Destroy() | ||
121 | { | ||
122 | PhysicalActors.Enable(false); | ||
123 | PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate() | ||
124 | { | ||
125 | PhysicalActors.Dispose(); | ||
126 | }); | ||
127 | } | ||
128 | |||
129 | public BSScene PhysScene { get; protected set; } | ||
130 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor | ||
131 | public string PhysObjectName { get; protected set; } | ||
132 | public string TypeName { get; protected set; } | ||
133 | |||
134 | // Set to 'true' when the object is completely initialized. | ||
135 | // This mostly prevents property updates and collisions until the object is completely here. | ||
136 | public bool IsInitialized { get; protected set; } | ||
137 | |||
138 | // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed. | ||
139 | // This test is used to prevent some updates to the object when it only partially exists. | ||
140 | // There are several reasons and object might be incomplete: | ||
141 | // Its underlying mesh/sculpty is an asset which must be fetched from the asset store | ||
142 | // It is a linkset who is being added to or removed from | ||
143 | // It is changing state (static to physical, for instance) which requires rebuilding | ||
144 | // This is a computed value based on the underlying physical object construction | ||
145 | abstract public bool IsIncomplete { get; } | ||
146 | |||
147 | // Return the object mass without calculating it or having side effects | ||
148 | public abstract float RawMass { get; } | ||
149 | // Set the raw mass but also update physical mass properties (inertia, ...) | ||
150 | // 'inWorld' true if the object has already been added to the dynamic world. | ||
151 | public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); | ||
152 | |||
153 | // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy. | ||
154 | public virtual OMV.Vector3 Gravity { get; set; } | ||
155 | // The last value calculated for the prim's inertia | ||
156 | public OMV.Vector3 Inertia { get; set; } | ||
157 | |||
158 | // Reference to the physical body (btCollisionObject) of this object | ||
159 | public BulletBody PhysBody = new BulletBody(0); | ||
160 | // Reference to the physical shape (btCollisionShape) of this object | ||
161 | public BSShape PhysShape = new BSShapeNull(); | ||
162 | |||
163 | // The physical representation of the prim might require an asset fetch. | ||
164 | // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. | ||
165 | public enum PrimAssetCondition | ||
166 | { | ||
167 | Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched | ||
168 | } | ||
169 | public PrimAssetCondition PrimAssetState { get; set; } | ||
170 | public virtual bool AssetFailed() | ||
171 | { | ||
172 | return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch) | ||
173 | || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) ); | ||
174 | } | ||
175 | |||
176 | // The objects base shape information. Null if not a prim type shape. | ||
177 | public PrimitiveBaseShape BaseShape { get; protected set; } | ||
178 | |||
179 | // When the physical properties are updated, an EntityProperty holds the update values. | ||
180 | // Keep the current and last EntityProperties to enable computation of differences | ||
181 | // between the current update and the previous values. | ||
182 | public EntityProperties CurrentEntityProperties { get; set; } | ||
183 | public EntityProperties LastEntityProperties { get; set; } | ||
184 | |||
185 | public virtual OMV.Vector3 Scale { get; set; } | ||
186 | |||
187 | // It can be confusing for an actor to know if it should move or update an object | ||
188 | // depeneding on the setting of 'selected', 'physical, ... | ||
189 | // This flag is the true test -- if true, the object is being acted on in the physical world | ||
190 | public abstract bool IsPhysicallyActive { get; } | ||
191 | |||
192 | // Detailed state of the object. | ||
193 | public abstract bool IsSolid { get; } | ||
194 | public abstract bool IsStatic { get; } | ||
195 | public abstract bool IsSelected { get; } | ||
196 | public abstract bool IsVolumeDetect { get; } | ||
197 | |||
198 | // Materialness | ||
199 | public MaterialAttributes.Material Material { get; private set; } | ||
200 | public override void SetMaterial(int material) | ||
201 | { | ||
202 | Material = (MaterialAttributes.Material)material; | ||
203 | |||
204 | // Setting the material sets the material attributes also. | ||
205 | // TODO: decide if this is necessary -- the simulator does this. | ||
206 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | ||
207 | Friction = matAttrib.friction; | ||
208 | Restitution = matAttrib.restitution; | ||
209 | Density = matAttrib.density; | ||
210 | // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); | ||
211 | } | ||
212 | |||
213 | public override float Density | ||
214 | { | ||
215 | get | ||
216 | { | ||
217 | return base.Density; | ||
218 | } | ||
219 | set | ||
220 | { | ||
221 | DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value); | ||
222 | base.Density = value; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | // Stop all physical motion. | ||
227 | public abstract void ZeroMotion(bool inTaintTime); | ||
228 | public abstract void ZeroAngularMotion(bool inTaintTime); | ||
229 | |||
230 | // Update the physical location and motion of the object. Called with data from Bullet. | ||
231 | public abstract void UpdateProperties(EntityProperties entprop); | ||
232 | |||
233 | public virtual OMV.Vector3 RawPosition { get; set; } | ||
234 | public abstract OMV.Vector3 ForcePosition { get; set; } | ||
235 | |||
236 | public virtual OMV.Quaternion RawOrientation { get; set; } | ||
237 | public abstract OMV.Quaternion ForceOrientation { get; set; } | ||
238 | |||
239 | public virtual OMV.Vector3 RawVelocity { get; set; } | ||
240 | public abstract OMV.Vector3 ForceVelocity { get; set; } | ||
241 | |||
242 | public OMV.Vector3 RawForce { get; set; } | ||
243 | public OMV.Vector3 RawTorque { get; set; } | ||
244 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) | ||
245 | { | ||
246 | AddAngularForce(force, pushforce, false); | ||
247 | } | ||
248 | public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); | ||
249 | public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); | ||
250 | |||
251 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | ||
252 | |||
253 | public abstract float ForceBuoyancy { get; set; } | ||
254 | |||
255 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | ||
256 | |||
257 | public override bool PIDActive | ||
258 | { | ||
259 | get { return MoveToTargetActive; } | ||
260 | set { MoveToTargetActive = value; } | ||
261 | } | ||
262 | |||
263 | public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } } | ||
264 | public override float PIDTau { set { MoveToTargetTau = value; } } | ||
265 | |||
266 | public bool MoveToTargetActive { get; set; } | ||
267 | public OMV.Vector3 MoveToTargetTarget { get; set; } | ||
268 | public float MoveToTargetTau { get; set; } | ||
269 | |||
270 | // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z | ||
271 | public override bool PIDHoverActive { set { HoverActive = value; } } | ||
272 | public override float PIDHoverHeight { set { HoverHeight = value; } } | ||
273 | public override PIDHoverType PIDHoverType { set { HoverType = value; } } | ||
274 | public override float PIDHoverTau { set { HoverTau = value; } } | ||
275 | |||
276 | public bool HoverActive { get; set; } | ||
277 | public float HoverHeight { get; set; } | ||
278 | public PIDHoverType HoverType { get; set; } | ||
279 | public float HoverTau { get; set; } | ||
280 | |||
281 | // For RotLookAt | ||
282 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
283 | public override bool APIDActive { set { return; } } | ||
284 | public override float APIDStrength { set { return; } } | ||
285 | public override float APIDDamping { set { return; } } | ||
286 | |||
287 | // The current velocity forward | ||
288 | public virtual float ForwardSpeed | ||
289 | { | ||
290 | get | ||
291 | { | ||
292 | OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); | ||
293 | return characterOrientedVelocity.X; | ||
294 | } | ||
295 | } | ||
296 | // The forward speed we are trying to achieve (TargetVelocity) | ||
297 | public virtual float TargetVelocitySpeed | ||
298 | { | ||
299 | get | ||
300 | { | ||
301 | OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); | ||
302 | return characterOrientedVelocity.X; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | // The user can optionally set the center of mass. The user's setting will override any | ||
307 | // computed center-of-mass (like in linksets). | ||
308 | // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. | ||
309 | public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } | ||
310 | |||
311 | public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free. | ||
312 | public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free. | ||
313 | public const float FreeAxis = 1f; | ||
314 | public const float LockedAxis = 0f; | ||
315 | public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free | ||
316 | |||
317 | // If an axis is locked (flagged above) then the limits of that axis are specified here. | ||
318 | // Linear axis limits are relative to the object's starting coordinates. | ||
319 | // Angular limits are limited to -PI to +PI | ||
320 | public OMV.Vector3 LockedLinearAxisLow; | ||
321 | public OMV.Vector3 LockedLinearAxisHigh; | ||
322 | public OMV.Vector3 LockedAngularAxisLow; | ||
323 | public OMV.Vector3 LockedAngularAxisHigh; | ||
324 | |||
325 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
326 | // they need waking up when parameters are changed. | ||
327 | // Called in taint-time!! | ||
328 | public void ActivateIfPhysical(bool forceIt) | ||
329 | { | ||
330 | if (PhysBody.HasPhysicalBody) | ||
331 | { | ||
332 | if (IsPhysical) | ||
333 | { | ||
334 | // Physical objects might need activating | ||
335 | PhysScene.PE.Activate(PhysBody, forceIt); | ||
336 | } | ||
337 | else | ||
338 | { | ||
339 | // Clear the collision cache since we've changed some properties. | ||
340 | PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody); | ||
341 | } | ||
342 | } | ||
343 | } | ||
344 | |||
345 | // 'actors' act on the physical object to change or constrain its motion. These can range from | ||
346 | // hovering to complex vehicle motion. | ||
347 | // May be called at non-taint time as this just adds the actor to the action list and the real | ||
348 | // work is done during the simulation step. | ||
349 | // Note that, if the actor is already in the list and we are disabling same, the actor is just left | ||
350 | // in the list disabled. | ||
351 | public delegate BSActor CreateActor(); | ||
352 | public void EnableActor(bool enableActor, string actorName, CreateActor creator) | ||
353 | { | ||
354 | lock (PhysicalActors) | ||
355 | { | ||
356 | BSActor theActor; | ||
357 | if (PhysicalActors.TryGetActor(actorName, out theActor)) | ||
358 | { | ||
359 | // The actor already exists so just turn it on or off | ||
360 | DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); | ||
361 | theActor.Enabled = enableActor; | ||
362 | } | ||
363 | else | ||
364 | { | ||
365 | // The actor does not exist. If it should, create it. | ||
366 | if (enableActor) | ||
367 | { | ||
368 | DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); | ||
369 | theActor = creator(); | ||
370 | PhysicalActors.Add(actorName, theActor); | ||
371 | theActor.Enabled = true; | ||
372 | } | ||
373 | else | ||
374 | { | ||
375 | DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); | ||
376 | } | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | |||
381 | #region Collisions | ||
382 | |||
383 | // Requested number of milliseconds between collision events. Zero means disabled. | ||
384 | protected int SubscribedEventsMs { get; set; } | ||
385 | // Given subscription, the time that a collision may be passed up | ||
386 | protected int NextCollisionOkTime { get; set; } | ||
387 | // The simulation step that last had a collision | ||
388 | protected long CollidingStep { get; set; } | ||
389 | // The simulation step that last had a collision with the ground | ||
390 | protected long CollidingGroundStep { get; set; } | ||
391 | // The simulation step that last collided with an object | ||
392 | protected long CollidingObjectStep { get; set; } | ||
393 | // The collision flags we think are set in Bullet | ||
394 | protected CollisionFlags CurrentCollisionFlags { get; set; } | ||
395 | // On a collision, check the collider and remember if the last collider was moving | ||
396 | // Used to modify the standing of avatars (avatars on stationary things stand still) | ||
397 | public bool ColliderIsMoving; | ||
398 | // 'true' if the last collider was a volume detect object | ||
399 | public bool ColliderIsVolumeDetect; | ||
400 | // Used by BSCharacter to manage standing (and not slipping) | ||
401 | public bool IsStationary; | ||
402 | |||
403 | // Count of collisions for this object | ||
404 | protected long CollisionAccumulation { get; set; } | ||
405 | |||
406 | public override bool IsColliding { | ||
407 | get { return (CollidingStep == PhysScene.SimulationStep); } | ||
408 | set { | ||
409 | if (value) | ||
410 | CollidingStep = PhysScene.SimulationStep; | ||
411 | else | ||
412 | CollidingStep = BSScene.NotASimulationStep; | ||
413 | } | ||
414 | } | ||
415 | // Complex objects (like linksets) need to know if there is a collision on any part of | ||
416 | // their shape. 'IsColliding' has an existing definition of reporting a collision on | ||
417 | // only this specific prim or component of linksets. | ||
418 | // 'HasSomeCollision' is defined as reporting if there is a collision on any part of | ||
419 | // the complex body that this prim is the root of. | ||
420 | public virtual bool HasSomeCollision | ||
421 | { | ||
422 | get { return IsColliding; } | ||
423 | set { IsColliding = value; } | ||
424 | } | ||
425 | public override bool CollidingGround { | ||
426 | get { return (CollidingGroundStep == PhysScene.SimulationStep); } | ||
427 | set | ||
428 | { | ||
429 | if (value) | ||
430 | CollidingGroundStep = PhysScene.SimulationStep; | ||
431 | else | ||
432 | CollidingGroundStep = BSScene.NotASimulationStep; | ||
433 | } | ||
434 | } | ||
435 | public override bool CollidingObj { | ||
436 | get { return (CollidingObjectStep == PhysScene.SimulationStep); } | ||
437 | set { | ||
438 | if (value) | ||
439 | CollidingObjectStep = PhysScene.SimulationStep; | ||
440 | else | ||
441 | CollidingObjectStep = BSScene.NotASimulationStep; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | // The collisions that have been collected for the next collision reporting (throttled by subscription) | ||
446 | protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate(); | ||
447 | // This is the collision collection last reported to the Simulator. | ||
448 | public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate(); | ||
449 | // Remember the collisions recorded in the last tick for fancy collision checking | ||
450 | // (like a BSCharacter walking up stairs). | ||
451 | public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate(); | ||
452 | private long CollisionsLastTickStep = -1; | ||
453 | |||
454 | // The simulation step is telling this object about a collision. | ||
455 | // Return 'true' if a collision was processed and should be sent up. | ||
456 | // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. | ||
457 | // Called at taint time from within the Step() function | ||
458 | public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); | ||
459 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, | ||
460 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
461 | { | ||
462 | bool ret = false; | ||
463 | |||
464 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work | ||
465 | CollidingStep = PhysScene.SimulationStep; | ||
466 | if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) | ||
467 | { | ||
468 | CollidingGroundStep = PhysScene.SimulationStep; | ||
469 | } | ||
470 | else | ||
471 | { | ||
472 | CollidingObjectStep = PhysScene.SimulationStep; | ||
473 | } | ||
474 | |||
475 | CollisionAccumulation++; | ||
476 | |||
477 | // For movement tests, remember if we are colliding with an object that is moving. | ||
478 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; | ||
479 | ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; | ||
480 | |||
481 | // Make a collection of the collisions that happened the last simulation tick. | ||
482 | // This is different than the collection created for sending up to the simulator as it is cleared every tick. | ||
483 | if (CollisionsLastTickStep != PhysScene.SimulationStep) | ||
484 | { | ||
485 | CollisionsLastTick = new CollisionEventUpdate(); | ||
486 | CollisionsLastTickStep = PhysScene.SimulationStep; | ||
487 | } | ||
488 | CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
489 | |||
490 | // If someone has subscribed for collision events log the collision so it will be reported up | ||
491 | if (SubscribedEvents()) { | ||
492 | lock (PhysScene.CollisionLock) | ||
493 | { | ||
494 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
495 | } | ||
496 | DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}", | ||
497 | LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving); | ||
498 | |||
499 | ret = true; | ||
500 | } | ||
501 | return ret; | ||
502 | } | ||
503 | |||
504 | // Send the collected collisions into the simulator. | ||
505 | // Called at taint time from within the Step() function thus no locking problems | ||
506 | // with CollisionCollection and ObjectsWithNoMoreCollisions. | ||
507 | // Called with BSScene.CollisionLock locked to protect the collision lists. | ||
508 | // Return 'true' if there were some actual collisions passed up | ||
509 | public virtual bool SendCollisions() | ||
510 | { | ||
511 | bool ret = true; | ||
512 | |||
513 | // If no collisions this call but there were collisions last call, force the collision | ||
514 | // event to be happen right now so quick collision_end. | ||
515 | bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); | ||
516 | |||
517 | // throttle the collisions to the number of milliseconds specified in the subscription | ||
518 | if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) | ||
519 | { | ||
520 | NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; | ||
521 | |||
522 | // We are called if we previously had collisions. If there are no collisions | ||
523 | // this time, send up one last empty event so OpenSim can sense collision end. | ||
524 | if (CollisionCollection.Count == 0) | ||
525 | { | ||
526 | // If I have no collisions this time, remove me from the list of objects with collisions. | ||
527 | ret = false; | ||
528 | } | ||
529 | |||
530 | DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); | ||
531 | base.SendCollisionUpdate(CollisionCollection); | ||
532 | |||
533 | // Remember the collisions from this tick for some collision specific processing. | ||
534 | CollisionsLastReported = CollisionCollection; | ||
535 | |||
536 | // The CollisionCollection instance is passed around in the simulator. | ||
537 | // Make sure we don't have a handle to that one and that a new one is used for next time. | ||
538 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | ||
539 | // a race condition is created for the other users of this instance. | ||
540 | CollisionCollection = new CollisionEventUpdate(); | ||
541 | } | ||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | // Subscribe for collision events. | ||
546 | // Parameter is the millisecond rate the caller wishes collision events to occur. | ||
547 | public override void SubscribeEvents(int ms) { | ||
548 | // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms); | ||
549 | SubscribedEventsMs = ms; | ||
550 | if (ms > 0) | ||
551 | { | ||
552 | // make sure first collision happens | ||
553 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); | ||
554 | |||
555 | PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate() | ||
556 | { | ||
557 | if (PhysBody.HasPhysicalBody) | ||
558 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
559 | }); | ||
560 | } | ||
561 | else | ||
562 | { | ||
563 | // Subscribing for zero or less is the same as unsubscribing | ||
564 | UnSubscribeEvents(); | ||
565 | } | ||
566 | } | ||
567 | public override void UnSubscribeEvents() { | ||
568 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); | ||
569 | SubscribedEventsMs = 0; | ||
570 | PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate() | ||
571 | { | ||
572 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. | ||
573 | if (PhysBody.HasPhysicalBody) | ||
574 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
575 | }); | ||
576 | } | ||
577 | // Return 'true' if the simulator wants collision events | ||
578 | public override bool SubscribedEvents() { | ||
579 | return (SubscribedEventsMs > 0); | ||
580 | } | ||
581 | // Because 'CollisionScore' is called many times while sorting, it should not be recomputed | ||
582 | // each time called. So this is built to be light weight for each collision and to do | ||
583 | // all the processing when the user asks for the info. | ||
584 | public void ComputeCollisionScore() | ||
585 | { | ||
586 | // Scale the collision count by the time since the last collision. | ||
587 | // The "+1" prevents dividing by zero. | ||
588 | long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; | ||
589 | CollisionScore = CollisionAccumulation / timeAgo; | ||
590 | } | ||
591 | public override float CollisionScore { get; set; } | ||
592 | |||
593 | #endregion // Collisions | ||
594 | |||
595 | #region Per Simulation Step actions | ||
596 | |||
597 | public BSActorCollection PhysicalActors = new BSActorCollection(); | ||
598 | |||
599 | // When an update to the physical properties happens, this event is fired to let | ||
600 | // different actors to modify the update before it is passed around | ||
601 | public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); | ||
602 | public event PreUpdatePropertyAction OnPreUpdateProperty; | ||
603 | protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop) | ||
604 | { | ||
605 | PreUpdatePropertyAction actions = OnPreUpdateProperty; | ||
606 | if (actions != null) | ||
607 | actions(ref entprop); | ||
608 | } | ||
609 | |||
610 | #endregion // Per Simulation Step actions | ||
611 | |||
612 | // High performance detailed logging routine used by the physical objects. | ||
613 | protected void DetailLog(string msg, params Object[] args) | ||
614 | { | ||
615 | if (PhysScene.PhysicsLogging.Enabled) | ||
616 | PhysScene.DetailLog(msg, args); | ||
617 | } | ||
618 | |||
619 | } | ||
620 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs new file mode 100644 index 0000000..9442854 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs | |||
@@ -0,0 +1,76 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using OpenSim.Framework; | ||
30 | using OpenSim.Region.Physics.Manager; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. | ||
37 | /// This module interfaces to an unmanaged C++ library which makes the | ||
38 | /// actual calls into the Bullet physics engine. | ||
39 | /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. | ||
40 | /// The unmanaged library is compiled and linked statically with Bullet | ||
41 | /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit). | ||
42 | /// </summary> | ||
43 | public class BSPlugin : IPhysicsPlugin | ||
44 | { | ||
45 | //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | |||
47 | private BSScene _mScene; | ||
48 | |||
49 | public BSPlugin() | ||
50 | { | ||
51 | } | ||
52 | |||
53 | public bool Init() | ||
54 | { | ||
55 | return true; | ||
56 | } | ||
57 | |||
58 | public PhysicsScene GetScene(String sceneIdentifier) | ||
59 | { | ||
60 | if (_mScene == null) | ||
61 | { | ||
62 | _mScene = new BSScene(GetName(), sceneIdentifier); | ||
63 | } | ||
64 | return (_mScene); | ||
65 | } | ||
66 | |||
67 | public string GetName() | ||
68 | { | ||
69 | return ("BulletSim"); | ||
70 | } | ||
71 | |||
72 | public void Dispose() | ||
73 | { | ||
74 | } | ||
75 | } | ||
76 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs new file mode 100644 index 0000000..a00991f --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs | |||
@@ -0,0 +1,1896 @@ | |||
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 copyrightD | ||
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.Reflection; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Xml; | ||
32 | using log4net; | ||
33 | using OMV = OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.Physics.Manager; | ||
36 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
37 | using OpenSim.Region.OptionalModules.Scripting; // for ExtendedPhysics | ||
38 | |||
39 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
40 | { | ||
41 | |||
42 | [Serializable] | ||
43 | public class BSPrim : BSPhysObject | ||
44 | { | ||
45 | protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | private static readonly string LogHeader = "[BULLETS PRIM]"; | ||
47 | |||
48 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. | ||
49 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | ||
50 | |||
51 | private bool _grabbed; | ||
52 | private bool _isSelected; | ||
53 | private bool _isVolumeDetect; | ||
54 | |||
55 | private float _mass; // the mass of this object | ||
56 | private OMV.Vector3 _acceleration; | ||
57 | private int _physicsActorType; | ||
58 | private bool _isPhysical; | ||
59 | private bool _flying; | ||
60 | private bool _setAlwaysRun; | ||
61 | private bool _throttleUpdates; | ||
62 | private bool _floatOnWater; | ||
63 | private OMV.Vector3 _rotationalVelocity; | ||
64 | private bool _kinematic; | ||
65 | private float _buoyancy; | ||
66 | |||
67 | private int CrossingFailures { get; set; } | ||
68 | |||
69 | // Keep a handle to the vehicle actor so it is easy to set parameters on same. | ||
70 | public const string VehicleActorName = "BasicVehicle"; | ||
71 | |||
72 | // Parameters for the hover actor | ||
73 | public const string HoverActorName = "BSPrim.HoverActor"; | ||
74 | // Parameters for the axis lock actor | ||
75 | public const String LockedAxisActorName = "BSPrim.LockedAxis"; | ||
76 | // Parameters for the move to target actor | ||
77 | public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor"; | ||
78 | // Parameters for the setForce and setTorque actors | ||
79 | public const string SetForceActorName = "BSPrim.SetForceActor"; | ||
80 | public const string SetTorqueActorName = "BSPrim.SetTorqueActor"; | ||
81 | |||
82 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
83 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
84 | : base(parent_scene, localID, primName, "BSPrim") | ||
85 | { | ||
86 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); | ||
87 | _physicsActorType = (int)ActorTypes.Prim; | ||
88 | RawPosition = pos; | ||
89 | _size = size; | ||
90 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). | ||
91 | RawOrientation = rotation; | ||
92 | _buoyancy = 0f; | ||
93 | RawVelocity = OMV.Vector3.Zero; | ||
94 | _rotationalVelocity = OMV.Vector3.Zero; | ||
95 | BaseShape = pbs; | ||
96 | _isPhysical = pisPhysical; | ||
97 | _isVolumeDetect = false; | ||
98 | |||
99 | _mass = CalculateMass(); | ||
100 | |||
101 | DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs)); | ||
102 | // DetailLog("{0},BSPrim.constructor,call", LocalID); | ||
103 | // do the actual object creation at taint time | ||
104 | PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate() | ||
105 | { | ||
106 | // Make sure the object is being created with some sanity. | ||
107 | ExtremeSanityCheck(true /* inTaintTime */); | ||
108 | |||
109 | CreateGeomAndObject(true); | ||
110 | |||
111 | CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); | ||
112 | |||
113 | IsInitialized = true; | ||
114 | }); | ||
115 | } | ||
116 | |||
117 | // called when this prim is being destroyed and we should free all the resources | ||
118 | public override void Destroy() | ||
119 | { | ||
120 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | ||
121 | IsInitialized = false; | ||
122 | |||
123 | base.Destroy(); | ||
124 | |||
125 | // Undo any vehicle properties | ||
126 | this.VehicleType = (int)Vehicle.TYPE_NONE; | ||
127 | |||
128 | PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate() | ||
129 | { | ||
130 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | ||
131 | // If there are physical body and shape, release my use of same. | ||
132 | PhysScene.Shapes.DereferenceBody(PhysBody, null); | ||
133 | PhysBody.Clear(); | ||
134 | PhysShape.Dereference(PhysScene); | ||
135 | PhysShape = new BSShapeNull(); | ||
136 | }); | ||
137 | } | ||
138 | |||
139 | // No one uses this property. | ||
140 | public override bool Stopped { | ||
141 | get { return false; } | ||
142 | } | ||
143 | |||
144 | public override bool IsIncomplete { | ||
145 | get { | ||
146 | return ShapeRebuildScheduled; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued. | ||
151 | // The prim is still available but its underlying shape will change soon. | ||
152 | // This is protected by a 'lock(this)'. | ||
153 | public bool ShapeRebuildScheduled { get; protected set; } | ||
154 | |||
155 | public override OMV.Vector3 Size { | ||
156 | get { return _size; } | ||
157 | set { | ||
158 | // We presume the scale and size are the same. If scale must be changed for | ||
159 | // the physical shape, that is done when the geometry is built. | ||
160 | _size = value; | ||
161 | Scale = _size; | ||
162 | ForceBodyShapeRebuild(false); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | public override PrimitiveBaseShape Shape { | ||
167 | set { | ||
168 | BaseShape = value; | ||
169 | DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape)); | ||
170 | PrimAssetState = PrimAssetCondition.Unknown; | ||
171 | ForceBodyShapeRebuild(false); | ||
172 | } | ||
173 | } | ||
174 | // Cause the body and shape of the prim to be rebuilt if necessary. | ||
175 | // If there are no changes required, this is quick and does not make changes to the prim. | ||
176 | // If rebuilding is necessary (like changing from static to physical), that will happen. | ||
177 | // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly. | ||
178 | // The return parameter is not used by anyone. | ||
179 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | ||
180 | { | ||
181 | if (inTaintTime) | ||
182 | { | ||
183 | // If called in taint time, do the operation immediately | ||
184 | _mass = CalculateMass(); // changing the shape changes the mass | ||
185 | CreateGeomAndObject(true); | ||
186 | } | ||
187 | else | ||
188 | { | ||
189 | lock (this) | ||
190 | { | ||
191 | // If a rebuild is not already in the queue | ||
192 | if (!ShapeRebuildScheduled) | ||
193 | { | ||
194 | // Remember that a rebuild is queued -- this is used to flag an incomplete object | ||
195 | ShapeRebuildScheduled = true; | ||
196 | PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate() | ||
197 | { | ||
198 | _mass = CalculateMass(); // changing the shape changes the mass | ||
199 | CreateGeomAndObject(true); | ||
200 | ShapeRebuildScheduled = false; | ||
201 | }); | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | return true; | ||
206 | } | ||
207 | public override bool Grabbed { | ||
208 | set { _grabbed = value; | ||
209 | } | ||
210 | } | ||
211 | public override bool Selected { | ||
212 | set | ||
213 | { | ||
214 | if (value != _isSelected) | ||
215 | { | ||
216 | _isSelected = value; | ||
217 | PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate() | ||
218 | { | ||
219 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | ||
220 | SetObjectDynamic(false); | ||
221 | }); | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | public override bool IsSelected | ||
226 | { | ||
227 | get { return _isSelected; } | ||
228 | } | ||
229 | |||
230 | public override void CrossingFailure() | ||
231 | { | ||
232 | CrossingFailures++; | ||
233 | if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds) | ||
234 | { | ||
235 | base.RaiseOutOfBounds(RawPosition); | ||
236 | } | ||
237 | else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds) | ||
238 | { | ||
239 | m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name); | ||
240 | } | ||
241 | return; | ||
242 | } | ||
243 | |||
244 | // link me to the specified parent | ||
245 | public override void link(PhysicsActor obj) { | ||
246 | } | ||
247 | |||
248 | // delink me from my linkset | ||
249 | public override void delink() { | ||
250 | } | ||
251 | |||
252 | // Set motion values to zero. | ||
253 | // Do it to the properties so the values get set in the physics engine. | ||
254 | // Push the setting of the values to the viewer. | ||
255 | // Called at taint time! | ||
256 | public override void ZeroMotion(bool inTaintTime) | ||
257 | { | ||
258 | RawVelocity = OMV.Vector3.Zero; | ||
259 | _acceleration = OMV.Vector3.Zero; | ||
260 | _rotationalVelocity = OMV.Vector3.Zero; | ||
261 | |||
262 | // Zero some other properties in the physics engine | ||
263 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() | ||
264 | { | ||
265 | if (PhysBody.HasPhysicalBody) | ||
266 | PhysScene.PE.ClearAllForces(PhysBody); | ||
267 | }); | ||
268 | } | ||
269 | public override void ZeroAngularMotion(bool inTaintTime) | ||
270 | { | ||
271 | _rotationalVelocity = OMV.Vector3.Zero; | ||
272 | // Zero some other properties in the physics engine | ||
273 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() | ||
274 | { | ||
275 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); | ||
276 | if (PhysBody.HasPhysicalBody) | ||
277 | { | ||
278 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | ||
279 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | ||
280 | } | ||
281 | }); | ||
282 | } | ||
283 | |||
284 | public override void LockAngularMotion(OMV.Vector3 axis) | ||
285 | { | ||
286 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | ||
287 | |||
288 | ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); | ||
289 | if (axis.X != 1) | ||
290 | { | ||
291 | ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f); | ||
292 | } | ||
293 | if (axis.Y != 1) | ||
294 | { | ||
295 | ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f); | ||
296 | } | ||
297 | if (axis.Z != 1) | ||
298 | { | ||
299 | ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f); | ||
300 | } | ||
301 | |||
302 | InitializeAxisActor(); | ||
303 | |||
304 | return; | ||
305 | } | ||
306 | |||
307 | public override OMV.Vector3 Position { | ||
308 | get { | ||
309 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. | ||
310 | // RawPosition = ForcePosition; | ||
311 | return RawPosition; | ||
312 | } | ||
313 | set { | ||
314 | // If the position must be forced into the physics engine, use ForcePosition. | ||
315 | // All positions are given in world positions. | ||
316 | if (RawPosition == value) | ||
317 | { | ||
318 | DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); | ||
319 | return; | ||
320 | } | ||
321 | RawPosition = value; | ||
322 | PositionSanityCheck(false); | ||
323 | |||
324 | PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate() | ||
325 | { | ||
326 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); | ||
327 | ForcePosition = RawPosition; | ||
328 | }); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity. | ||
333 | public override OMV.Vector3 ForcePosition { | ||
334 | get { | ||
335 | RawPosition = PhysScene.PE.GetPosition(PhysBody); | ||
336 | return RawPosition; | ||
337 | } | ||
338 | set { | ||
339 | RawPosition = value; | ||
340 | if (PhysBody.HasPhysicalBody) | ||
341 | { | ||
342 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); | ||
343 | ActivateIfPhysical(false); | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | // Check that the current position is sane and, if not, modify the position to make it so. | ||
349 | // Check for being below terrain and being out of bounds. | ||
350 | // Returns 'true' of the position was made sane by some action. | ||
351 | private bool PositionSanityCheck(bool inTaintTime) | ||
352 | { | ||
353 | bool ret = false; | ||
354 | |||
355 | // We don't care where non-physical items are placed | ||
356 | if (!IsPhysicallyActive) | ||
357 | return ret; | ||
358 | |||
359 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | ||
360 | { | ||
361 | // The physical object is out of the known/simulated area. | ||
362 | // Upper levels of code will handle the transition to other areas so, for | ||
363 | // the time, we just ignore the position. | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | ||
368 | OMV.Vector3 upForce = OMV.Vector3.Zero; | ||
369 | float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); | ||
370 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) | ||
371 | { | ||
372 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); | ||
373 | float targetHeight = terrainHeight + (Size.Z / 2f); | ||
374 | // If the object is below ground it just has to be moved up because pushing will | ||
375 | // not get it through the terrain | ||
376 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight); | ||
377 | if (inTaintTime) | ||
378 | { | ||
379 | ForcePosition = RawPosition; | ||
380 | } | ||
381 | // If we are throwing the object around, zero its other forces | ||
382 | ZeroMotion(inTaintTime); | ||
383 | ret = true; | ||
384 | } | ||
385 | |||
386 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
387 | { | ||
388 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); | ||
389 | // TODO: a floating motor so object will bob in the water | ||
390 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) | ||
391 | { | ||
392 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. | ||
393 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; | ||
394 | |||
395 | // Apply upforce and overcome gravity. | ||
396 | OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; | ||
397 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce); | ||
398 | AddForce(correctionForce, false, inTaintTime); | ||
399 | ret = true; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | // Occasionally things will fly off and really get lost. | ||
407 | // Find the wanderers and bring them back. | ||
408 | // Return 'true' if some parameter need some sanity. | ||
409 | private bool ExtremeSanityCheck(bool inTaintTime) | ||
410 | { | ||
411 | bool ret = false; | ||
412 | |||
413 | int wayOverThere = -1000; | ||
414 | int wayOutThere = 10000; | ||
415 | // There have been instances of objects getting thrown way out of bounds and crashing | ||
416 | // the border crossing code. | ||
417 | if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere | ||
418 | || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere | ||
419 | || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere) | ||
420 | { | ||
421 | RawPosition = new OMV.Vector3(10, 10, 50); | ||
422 | ZeroMotion(inTaintTime); | ||
423 | ret = true; | ||
424 | } | ||
425 | if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared) | ||
426 | { | ||
427 | RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); | ||
428 | ret = true; | ||
429 | } | ||
430 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) | ||
431 | { | ||
432 | _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | ||
433 | ret = true; | ||
434 | } | ||
435 | |||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | // Return the effective mass of the object. | ||
440 | // The definition of this call is to return the mass of the prim. | ||
441 | // If the simulator cares about the mass of the linkset, it will sum it itself. | ||
442 | public override float Mass | ||
443 | { | ||
444 | get { return _mass; } | ||
445 | } | ||
446 | // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code) | ||
447 | public virtual float TotalMass | ||
448 | { | ||
449 | get { return _mass; } | ||
450 | } | ||
451 | // used when we only want this prim's mass and not the linkset thing | ||
452 | public override float RawMass { | ||
453 | get { return _mass; } | ||
454 | } | ||
455 | // Set the physical mass to the passed mass. | ||
456 | // Note that this does not change _mass! | ||
457 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | ||
458 | { | ||
459 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | ||
460 | { | ||
461 | if (IsStatic) | ||
462 | { | ||
463 | PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); | ||
464 | Inertia = OMV.Vector3.Zero; | ||
465 | PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); | ||
466 | PhysScene.PE.UpdateInertiaTensor(PhysBody); | ||
467 | } | ||
468 | else | ||
469 | { | ||
470 | if (inWorld) | ||
471 | { | ||
472 | // Changing interesting properties doesn't change proxy and collision cache | ||
473 | // information. The Bullet solution is to re-add the object to the world | ||
474 | // after parameters are changed. | ||
475 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); | ||
476 | } | ||
477 | |||
478 | // The computation of mass props requires gravity to be set on the object. | ||
479 | Gravity = ComputeGravity(Buoyancy); | ||
480 | PhysScene.PE.SetGravity(PhysBody, Gravity); | ||
481 | |||
482 | // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG | ||
483 | // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG | ||
484 | |||
485 | Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); | ||
486 | PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); | ||
487 | PhysScene.PE.UpdateInertiaTensor(PhysBody); | ||
488 | |||
489 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", | ||
490 | LocalID, physMass, Inertia, Gravity, inWorld); | ||
491 | |||
492 | if (inWorld) | ||
493 | { | ||
494 | AddObjectToPhysicalWorld(); | ||
495 | } | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | |||
500 | // Return what gravity should be set to this very moment | ||
501 | public OMV.Vector3 ComputeGravity(float buoyancy) | ||
502 | { | ||
503 | OMV.Vector3 ret = PhysScene.DefaultGravity; | ||
504 | |||
505 | if (!IsStatic) | ||
506 | { | ||
507 | ret *= (1f - buoyancy); | ||
508 | ret *= GravModifier; | ||
509 | } | ||
510 | |||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | // Is this used? | ||
515 | public override OMV.Vector3 CenterOfMass | ||
516 | { | ||
517 | get { return RawPosition; } | ||
518 | } | ||
519 | |||
520 | // Is this used? | ||
521 | public override OMV.Vector3 GeometricCenter | ||
522 | { | ||
523 | get { return RawPosition; } | ||
524 | } | ||
525 | |||
526 | public override OMV.Vector3 Force { | ||
527 | get { return RawForce; } | ||
528 | set { | ||
529 | RawForce = value; | ||
530 | EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() | ||
531 | { | ||
532 | return new BSActorSetForce(PhysScene, this, SetForceActorName); | ||
533 | }); | ||
534 | |||
535 | // Call update so actor Refresh() is called to start things off | ||
536 | PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate() | ||
537 | { | ||
538 | UpdatePhysicalParameters(); | ||
539 | }); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | // Find and return a handle to the current vehicle actor. | ||
544 | // Return 'null' if there is no vehicle actor. | ||
545 | public BSDynamics GetVehicleActor(bool createIfNone) | ||
546 | { | ||
547 | BSDynamics ret = null; | ||
548 | BSActor actor; | ||
549 | if (PhysicalActors.TryGetActor(VehicleActorName, out actor)) | ||
550 | { | ||
551 | ret = actor as BSDynamics; | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | if (createIfNone) | ||
556 | { | ||
557 | ret = new BSDynamics(PhysScene, this, VehicleActorName); | ||
558 | PhysicalActors.Add(ret.ActorName, ret); | ||
559 | } | ||
560 | } | ||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | public override int VehicleType { | ||
565 | get { | ||
566 | int ret = (int)Vehicle.TYPE_NONE; | ||
567 | BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); | ||
568 | if (vehicleActor != null) | ||
569 | ret = (int)vehicleActor.Type; | ||
570 | return ret; | ||
571 | } | ||
572 | set { | ||
573 | Vehicle type = (Vehicle)value; | ||
574 | |||
575 | PhysScene.TaintedObject(LocalID, "setVehicleType", delegate() | ||
576 | { | ||
577 | // Some vehicle scripts change vehicle type on the fly as an easy way to | ||
578 | // change all the parameters. Like a plane changing to CAR when on the | ||
579 | // ground. In this case, don't want to zero motion. | ||
580 | // ZeroMotion(true /* inTaintTime */); | ||
581 | if (type == Vehicle.TYPE_NONE) | ||
582 | { | ||
583 | // Vehicle type is 'none' so get rid of any actor that may have been allocated. | ||
584 | BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); | ||
585 | if (vehicleActor != null) | ||
586 | { | ||
587 | PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); | ||
588 | } | ||
589 | } | ||
590 | else | ||
591 | { | ||
592 | // Vehicle type is not 'none' so create an actor and set it running. | ||
593 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); | ||
594 | if (vehicleActor != null) | ||
595 | { | ||
596 | vehicleActor.ProcessTypeChange(type); | ||
597 | ActivateIfPhysical(false); | ||
598 | } | ||
599 | } | ||
600 | }); | ||
601 | } | ||
602 | } | ||
603 | public override void VehicleFloatParam(int param, float value) | ||
604 | { | ||
605 | PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate() | ||
606 | { | ||
607 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); | ||
608 | if (vehicleActor != null) | ||
609 | { | ||
610 | vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); | ||
611 | ActivateIfPhysical(false); | ||
612 | } | ||
613 | }); | ||
614 | } | ||
615 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | ||
616 | { | ||
617 | PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate() | ||
618 | { | ||
619 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); | ||
620 | if (vehicleActor != null) | ||
621 | { | ||
622 | vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); | ||
623 | ActivateIfPhysical(false); | ||
624 | } | ||
625 | }); | ||
626 | } | ||
627 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | ||
628 | { | ||
629 | PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate() | ||
630 | { | ||
631 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); | ||
632 | if (vehicleActor != null) | ||
633 | { | ||
634 | vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); | ||
635 | ActivateIfPhysical(false); | ||
636 | } | ||
637 | }); | ||
638 | } | ||
639 | public override void VehicleFlags(int param, bool remove) | ||
640 | { | ||
641 | PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate() | ||
642 | { | ||
643 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); | ||
644 | if (vehicleActor != null) | ||
645 | { | ||
646 | vehicleActor.ProcessVehicleFlags(param, remove); | ||
647 | } | ||
648 | }); | ||
649 | } | ||
650 | |||
651 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||
652 | public override void SetVolumeDetect(int param) { | ||
653 | bool newValue = (param != 0); | ||
654 | if (_isVolumeDetect != newValue) | ||
655 | { | ||
656 | _isVolumeDetect = newValue; | ||
657 | PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate() | ||
658 | { | ||
659 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | ||
660 | SetObjectDynamic(true); | ||
661 | }); | ||
662 | } | ||
663 | return; | ||
664 | } | ||
665 | public override bool IsVolumeDetect | ||
666 | { | ||
667 | get { return _isVolumeDetect; } | ||
668 | } | ||
669 | public override void SetMaterial(int material) | ||
670 | { | ||
671 | base.SetMaterial(material); | ||
672 | PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate() | ||
673 | { | ||
674 | UpdatePhysicalParameters(); | ||
675 | }); | ||
676 | } | ||
677 | public override float Friction | ||
678 | { | ||
679 | get { return base.Friction; } | ||
680 | set | ||
681 | { | ||
682 | if (base.Friction != value) | ||
683 | { | ||
684 | base.Friction = value; | ||
685 | PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate() | ||
686 | { | ||
687 | UpdatePhysicalParameters(); | ||
688 | }); | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | public override float Restitution | ||
693 | { | ||
694 | get { return base.Restitution; } | ||
695 | set | ||
696 | { | ||
697 | if (base.Restitution != value) | ||
698 | { | ||
699 | base.Restitution = value; | ||
700 | PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate() | ||
701 | { | ||
702 | UpdatePhysicalParameters(); | ||
703 | }); | ||
704 | } | ||
705 | } | ||
706 | } | ||
707 | // The simulator/viewer keep density as 100kg/m3. | ||
708 | // Remember to use BSParam.DensityScaleFactor to create the physical density. | ||
709 | public override float Density | ||
710 | { | ||
711 | get { return base.Density; } | ||
712 | set | ||
713 | { | ||
714 | if (base.Density != value) | ||
715 | { | ||
716 | base.Density = value; | ||
717 | PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate() | ||
718 | { | ||
719 | UpdatePhysicalParameters(); | ||
720 | }); | ||
721 | } | ||
722 | } | ||
723 | } | ||
724 | public override float GravModifier | ||
725 | { | ||
726 | get { return base.GravModifier; } | ||
727 | set | ||
728 | { | ||
729 | if (base.GravModifier != value) | ||
730 | { | ||
731 | base.GravModifier = value; | ||
732 | PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate() | ||
733 | { | ||
734 | UpdatePhysicalParameters(); | ||
735 | }); | ||
736 | } | ||
737 | } | ||
738 | } | ||
739 | public override OMV.Vector3 Velocity { | ||
740 | get { return RawVelocity; } | ||
741 | set { | ||
742 | RawVelocity = value; | ||
743 | PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate() | ||
744 | { | ||
745 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); | ||
746 | ForceVelocity = RawVelocity; | ||
747 | }); | ||
748 | } | ||
749 | } | ||
750 | public override OMV.Vector3 ForceVelocity { | ||
751 | get { return RawVelocity; } | ||
752 | set { | ||
753 | PhysScene.AssertInTaintTime("BSPrim.ForceVelocity"); | ||
754 | |||
755 | RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); | ||
756 | if (PhysBody.HasPhysicalBody) | ||
757 | { | ||
758 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); | ||
759 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); | ||
760 | ActivateIfPhysical(false); | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | public override OMV.Vector3 Torque { | ||
765 | get { return RawTorque; } | ||
766 | set { | ||
767 | RawTorque = value; | ||
768 | EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() | ||
769 | { | ||
770 | return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); | ||
771 | }); | ||
772 | DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); | ||
773 | |||
774 | // Call update so actor Refresh() is called to start things off | ||
775 | PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate() | ||
776 | { | ||
777 | UpdatePhysicalParameters(); | ||
778 | }); | ||
779 | } | ||
780 | } | ||
781 | public override OMV.Vector3 Acceleration { | ||
782 | get { return _acceleration; } | ||
783 | set { _acceleration = value; } | ||
784 | } | ||
785 | |||
786 | public override OMV.Quaternion Orientation { | ||
787 | get { | ||
788 | return RawOrientation; | ||
789 | } | ||
790 | set { | ||
791 | if (RawOrientation == value) | ||
792 | return; | ||
793 | RawOrientation = value; | ||
794 | |||
795 | PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate() | ||
796 | { | ||
797 | ForceOrientation = RawOrientation; | ||
798 | }); | ||
799 | } | ||
800 | } | ||
801 | // Go directly to Bullet to get/set the value. | ||
802 | public override OMV.Quaternion ForceOrientation | ||
803 | { | ||
804 | get | ||
805 | { | ||
806 | RawOrientation = PhysScene.PE.GetOrientation(PhysBody); | ||
807 | return RawOrientation; | ||
808 | } | ||
809 | set | ||
810 | { | ||
811 | RawOrientation = value; | ||
812 | if (PhysBody.HasPhysicalBody) | ||
813 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); | ||
814 | } | ||
815 | } | ||
816 | public override int PhysicsActorType { | ||
817 | get { return _physicsActorType; } | ||
818 | set { _physicsActorType = value; } | ||
819 | } | ||
820 | public override bool IsPhysical { | ||
821 | get { return _isPhysical; } | ||
822 | set { | ||
823 | if (_isPhysical != value) | ||
824 | { | ||
825 | _isPhysical = value; | ||
826 | PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate() | ||
827 | { | ||
828 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | ||
829 | SetObjectDynamic(true); | ||
830 | // whether phys-to-static or static-to-phys, the object is not moving. | ||
831 | ZeroMotion(true); | ||
832 | |||
833 | }); | ||
834 | } | ||
835 | } | ||
836 | } | ||
837 | |||
838 | // An object is static (does not move) if selected or not physical | ||
839 | public override bool IsStatic | ||
840 | { | ||
841 | get { return _isSelected || !IsPhysical; } | ||
842 | } | ||
843 | |||
844 | // An object is solid if it's not phantom and if it's not doing VolumeDetect | ||
845 | public override bool IsSolid | ||
846 | { | ||
847 | get { return !IsPhantom && !_isVolumeDetect; } | ||
848 | } | ||
849 | |||
850 | // The object is moving and is actively being dynamic in the physical world | ||
851 | public override bool IsPhysicallyActive | ||
852 | { | ||
853 | get { return !_isSelected && IsPhysical; } | ||
854 | } | ||
855 | |||
856 | // Make gravity work if the object is physical and not selected | ||
857 | // Called at taint-time!! | ||
858 | private void SetObjectDynamic(bool forceRebuild) | ||
859 | { | ||
860 | // Recreate the physical object if necessary | ||
861 | CreateGeomAndObject(forceRebuild); | ||
862 | } | ||
863 | |||
864 | // Convert the simulator's physical properties into settings on BulletSim objects. | ||
865 | // There are four flags we're interested in: | ||
866 | // IsStatic: Object does not move, otherwise the object has mass and moves | ||
867 | // isSolid: other objects bounce off of this object | ||
868 | // isVolumeDetect: other objects pass through but can generate collisions | ||
869 | // collisionEvents: whether this object returns collision events | ||
870 | // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters. | ||
871 | public virtual void UpdatePhysicalParameters() | ||
872 | { | ||
873 | if (!PhysBody.HasPhysicalBody) | ||
874 | { | ||
875 | // This would only happen if updates are called for during initialization when the body is not set up yet. | ||
876 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); | ||
877 | return; | ||
878 | } | ||
879 | |||
880 | // Mangling all the physical properties requires the object not be in the physical world. | ||
881 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | ||
882 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); | ||
883 | |||
884 | // Set up the object physicalness (does gravity and collisions move this object) | ||
885 | MakeDynamic(IsStatic); | ||
886 | |||
887 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | ||
888 | PhysicalActors.Refresh(); | ||
889 | |||
890 | // Arrange for collision events if the simulator wants them | ||
891 | EnableCollisions(SubscribedEvents()); | ||
892 | |||
893 | // Make solid or not (do things bounce off or pass through this object). | ||
894 | MakeSolid(IsSolid); | ||
895 | |||
896 | AddObjectToPhysicalWorld(); | ||
897 | |||
898 | // Rebuild its shape | ||
899 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); | ||
900 | |||
901 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", | ||
902 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), | ||
903 | CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); | ||
904 | } | ||
905 | |||
906 | // "Making dynamic" means changing to and from static. | ||
907 | // When static, gravity does not effect the object and it is fixed in space. | ||
908 | // When dynamic, the object can fall and be pushed by others. | ||
909 | // This is independent of its 'solidness' which controls what passes through | ||
910 | // this object and what interacts with it. | ||
911 | protected virtual void MakeDynamic(bool makeStatic) | ||
912 | { | ||
913 | if (makeStatic) | ||
914 | { | ||
915 | // Become a Bullet 'static' object type | ||
916 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | ||
917 | // Stop all movement | ||
918 | ZeroMotion(true); | ||
919 | |||
920 | // Set various physical properties so other object interact properly | ||
921 | PhysScene.PE.SetFriction(PhysBody, Friction); | ||
922 | PhysScene.PE.SetRestitution(PhysBody, Restitution); | ||
923 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | ||
924 | |||
925 | // Mass is zero which disables a bunch of physics stuff in Bullet | ||
926 | UpdatePhysicalMassProperties(0f, false); | ||
927 | // Set collision detection parameters | ||
928 | if (BSParam.CcdMotionThreshold > 0f) | ||
929 | { | ||
930 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | ||
931 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | ||
932 | } | ||
933 | |||
934 | // The activation state is 'disabled' so Bullet will not try to act on it. | ||
935 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); | ||
936 | // Start it out sleeping and physical actions could wake it up. | ||
937 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); | ||
938 | |||
939 | // This collides like a static object | ||
940 | PhysBody.collisionType = CollisionType.Static; | ||
941 | } | ||
942 | else | ||
943 | { | ||
944 | // Not a Bullet static object | ||
945 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | ||
946 | |||
947 | // Set various physical properties so other object interact properly | ||
948 | PhysScene.PE.SetFriction(PhysBody, Friction); | ||
949 | PhysScene.PE.SetRestitution(PhysBody, Restitution); | ||
950 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); | ||
951 | |||
952 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | ||
953 | // Since this can be called multiple times, only zero forces when becoming physical | ||
954 | // PhysicsScene.PE.ClearAllForces(BSBody); | ||
955 | |||
956 | // For good measure, make sure the transform is set through to the motion state | ||
957 | ForcePosition = RawPosition; | ||
958 | ForceVelocity = RawVelocity; | ||
959 | ForceRotationalVelocity = _rotationalVelocity; | ||
960 | |||
961 | // A dynamic object has mass | ||
962 | UpdatePhysicalMassProperties(RawMass, false); | ||
963 | |||
964 | // Set collision detection parameters | ||
965 | if (BSParam.CcdMotionThreshold > 0f) | ||
966 | { | ||
967 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | ||
968 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | ||
969 | } | ||
970 | |||
971 | // Various values for simulation limits | ||
972 | PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); | ||
973 | PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); | ||
974 | PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); | ||
975 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | ||
976 | |||
977 | // This collides like an object. | ||
978 | PhysBody.collisionType = CollisionType.Dynamic; | ||
979 | |||
980 | // Force activation of the object so Bullet will act on it. | ||
981 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | ||
982 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | ||
983 | } | ||
984 | } | ||
985 | |||
986 | // "Making solid" means that other object will not pass through this object. | ||
987 | // To make transparent, we create a Bullet ghost object. | ||
988 | // Note: This expects to be called from the UpdatePhysicalParameters() routine as | ||
989 | // the functions after this one set up the state of a possibly newly created collision body. | ||
990 | private void MakeSolid(bool makeSolid) | ||
991 | { | ||
992 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); | ||
993 | if (makeSolid) | ||
994 | { | ||
995 | // Verify the previous code created the correct shape for this type of thing. | ||
996 | if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) | ||
997 | { | ||
998 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
999 | } | ||
1000 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
1001 | } | ||
1002 | else | ||
1003 | { | ||
1004 | if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) | ||
1005 | { | ||
1006 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
1007 | } | ||
1008 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
1009 | |||
1010 | // Change collision info from a static object to a ghosty collision object | ||
1011 | PhysBody.collisionType = CollisionType.VolumeDetect; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | ||
1016 | private void EnableCollisions(bool wantsCollisionEvents) | ||
1017 | { | ||
1018 | if (wantsCollisionEvents) | ||
1019 | { | ||
1020 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
1021 | } | ||
1022 | else | ||
1023 | { | ||
1024 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
1025 | } | ||
1026 | } | ||
1027 | |||
1028 | // Add me to the physical world. | ||
1029 | // Object MUST NOT already be in the world. | ||
1030 | // This routine exists because some assorted properties get mangled by adding to the world. | ||
1031 | internal void AddObjectToPhysicalWorld() | ||
1032 | { | ||
1033 | if (PhysBody.HasPhysicalBody) | ||
1034 | { | ||
1035 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); | ||
1036 | } | ||
1037 | else | ||
1038 | { | ||
1039 | m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); | ||
1040 | DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); | ||
1041 | } | ||
1042 | } | ||
1043 | |||
1044 | // prims don't fly | ||
1045 | public override bool Flying { | ||
1046 | get { return _flying; } | ||
1047 | set { | ||
1048 | _flying = value; | ||
1049 | } | ||
1050 | } | ||
1051 | public override bool SetAlwaysRun { | ||
1052 | get { return _setAlwaysRun; } | ||
1053 | set { _setAlwaysRun = value; } | ||
1054 | } | ||
1055 | public override bool ThrottleUpdates { | ||
1056 | get { return _throttleUpdates; } | ||
1057 | set { _throttleUpdates = value; } | ||
1058 | } | ||
1059 | public bool IsPhantom { | ||
1060 | get { | ||
1061 | // SceneObjectPart removes phantom objects from the physics scene | ||
1062 | // so, although we could implement touching and such, we never | ||
1063 | // are invoked as a phantom object | ||
1064 | return false; | ||
1065 | } | ||
1066 | } | ||
1067 | public override bool FloatOnWater { | ||
1068 | set { | ||
1069 | _floatOnWater = value; | ||
1070 | PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate() | ||
1071 | { | ||
1072 | if (_floatOnWater) | ||
1073 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | ||
1074 | else | ||
1075 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | ||
1076 | }); | ||
1077 | } | ||
1078 | } | ||
1079 | public override OMV.Vector3 RotationalVelocity { | ||
1080 | get { | ||
1081 | return _rotationalVelocity; | ||
1082 | } | ||
1083 | set { | ||
1084 | _rotationalVelocity = value; | ||
1085 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | ||
1086 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | ||
1087 | PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate() | ||
1088 | { | ||
1089 | ForceRotationalVelocity = _rotationalVelocity; | ||
1090 | }); | ||
1091 | } | ||
1092 | } | ||
1093 | public override OMV.Vector3 ForceRotationalVelocity { | ||
1094 | get { | ||
1095 | return _rotationalVelocity; | ||
1096 | } | ||
1097 | set { | ||
1098 | _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity); | ||
1099 | if (PhysBody.HasPhysicalBody) | ||
1100 | { | ||
1101 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | ||
1102 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | ||
1103 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | ||
1104 | ActivateIfPhysical(false); | ||
1105 | } | ||
1106 | } | ||
1107 | } | ||
1108 | public override bool Kinematic { | ||
1109 | get { return _kinematic; } | ||
1110 | set { _kinematic = value; | ||
1111 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); | ||
1112 | } | ||
1113 | } | ||
1114 | public override float Buoyancy { | ||
1115 | get { return _buoyancy; } | ||
1116 | set { | ||
1117 | _buoyancy = value; | ||
1118 | PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate() | ||
1119 | { | ||
1120 | ForceBuoyancy = _buoyancy; | ||
1121 | }); | ||
1122 | } | ||
1123 | } | ||
1124 | public override float ForceBuoyancy { | ||
1125 | get { return _buoyancy; } | ||
1126 | set { | ||
1127 | _buoyancy = value; | ||
1128 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
1129 | // Force the recalculation of the various inertia,etc variables in the object | ||
1130 | UpdatePhysicalMassProperties(RawMass, true); | ||
1131 | DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity); | ||
1132 | ActivateIfPhysical(false); | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | public override bool PIDActive | ||
1137 | { | ||
1138 | get | ||
1139 | { | ||
1140 | return MoveToTargetActive; | ||
1141 | } | ||
1142 | |||
1143 | set | ||
1144 | { | ||
1145 | MoveToTargetActive = value; | ||
1146 | |||
1147 | EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() | ||
1148 | { | ||
1149 | return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); | ||
1150 | }); | ||
1151 | |||
1152 | // Call update so actor Refresh() is called to start things off | ||
1153 | PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate() | ||
1154 | { | ||
1155 | UpdatePhysicalParameters(); | ||
1156 | }); | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | public override OMV.Vector3 PIDTarget | ||
1161 | { | ||
1162 | set | ||
1163 | { | ||
1164 | base.PIDTarget = value; | ||
1165 | BSActor actor; | ||
1166 | if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor)) | ||
1167 | { | ||
1168 | // if the actor exists, tell it to refresh its values. | ||
1169 | actor.Refresh(); | ||
1170 | } | ||
1171 | |||
1172 | } | ||
1173 | } | ||
1174 | // Used for llSetHoverHeight and maybe vehicle height | ||
1175 | // Hover Height will override MoveTo target's Z | ||
1176 | public override bool PIDHoverActive { | ||
1177 | set { | ||
1178 | base.HoverActive = value; | ||
1179 | EnableActor(HoverActive, HoverActorName, delegate() | ||
1180 | { | ||
1181 | return new BSActorHover(PhysScene, this, HoverActorName); | ||
1182 | }); | ||
1183 | |||
1184 | // Call update so actor Refresh() is called to start things off | ||
1185 | PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate() | ||
1186 | { | ||
1187 | UpdatePhysicalParameters(); | ||
1188 | }); | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | ||
1193 | // Per documentation, max force is limited. | ||
1194 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | ||
1195 | |||
1196 | // Since this force is being applied in only one step, make this a force per second. | ||
1197 | addForce /= PhysScene.LastTimeStep; | ||
1198 | AddForce(addForce, pushforce, false /* inTaintTime */); | ||
1199 | } | ||
1200 | |||
1201 | // Applying a force just adds this to the total force on the object. | ||
1202 | // This added force will only last the next simulation tick. | ||
1203 | public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
1204 | // for an object, doesn't matter if force is a pushforce or not | ||
1205 | if (IsPhysicallyActive) | ||
1206 | { | ||
1207 | if (force.IsFinite()) | ||
1208 | { | ||
1209 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); | ||
1210 | |||
1211 | OMV.Vector3 addForce = force; | ||
1212 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate() | ||
1213 | { | ||
1214 | // Bullet adds this central force to the total force for this tick. | ||
1215 | // Deep down in Bullet: | ||
1216 | // linearVelocity += totalForce / mass * timeStep; | ||
1217 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); | ||
1218 | if (PhysBody.HasPhysicalBody) | ||
1219 | { | ||
1220 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); | ||
1221 | ActivateIfPhysical(false); | ||
1222 | } | ||
1223 | }); | ||
1224 | } | ||
1225 | else | ||
1226 | { | ||
1227 | m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
1228 | return; | ||
1229 | } | ||
1230 | } | ||
1231 | } | ||
1232 | |||
1233 | public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) { | ||
1234 | // for an object, doesn't matter if force is a pushforce or not | ||
1235 | if (!IsPhysicallyActive) | ||
1236 | { | ||
1237 | if (impulse.IsFinite()) | ||
1238 | { | ||
1239 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); | ||
1240 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); | ||
1241 | |||
1242 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate() | ||
1243 | { | ||
1244 | // Bullet adds this impulse immediately to the velocity | ||
1245 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); | ||
1246 | if (PhysBody.HasPhysicalBody) | ||
1247 | { | ||
1248 | PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); | ||
1249 | ActivateIfPhysical(false); | ||
1250 | } | ||
1251 | }); | ||
1252 | } | ||
1253 | else | ||
1254 | { | ||
1255 | m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
1256 | return; | ||
1257 | } | ||
1258 | } | ||
1259 | } | ||
1260 | |||
1261 | // BSPhysObject.AddAngularForce() | ||
1262 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | ||
1263 | { | ||
1264 | if (force.IsFinite()) | ||
1265 | { | ||
1266 | OMV.Vector3 angForce = force; | ||
1267 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate() | ||
1268 | { | ||
1269 | if (PhysBody.HasPhysicalBody) | ||
1270 | { | ||
1271 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); | ||
1272 | PhysScene.PE.ApplyTorque(PhysBody, angForce); | ||
1273 | ActivateIfPhysical(false); | ||
1274 | } | ||
1275 | }); | ||
1276 | } | ||
1277 | else | ||
1278 | { | ||
1279 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
1280 | return; | ||
1281 | } | ||
1282 | } | ||
1283 | |||
1284 | // A torque impulse. | ||
1285 | // ApplyTorqueImpulse adds torque directly to the angularVelocity. | ||
1286 | // AddAngularForce accumulates the force and applied it to the angular velocity all at once. | ||
1287 | // Computed as: angularVelocity += impulse * inertia; | ||
1288 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | ||
1289 | { | ||
1290 | OMV.Vector3 applyImpulse = impulse; | ||
1291 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate() | ||
1292 | { | ||
1293 | if (PhysBody.HasPhysicalBody) | ||
1294 | { | ||
1295 | PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); | ||
1296 | ActivateIfPhysical(false); | ||
1297 | } | ||
1298 | }); | ||
1299 | } | ||
1300 | |||
1301 | public override void SetMomentum(OMV.Vector3 momentum) { | ||
1302 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); | ||
1303 | } | ||
1304 | #region Mass Calculation | ||
1305 | |||
1306 | private float CalculateMass() | ||
1307 | { | ||
1308 | float volume = _size.X * _size.Y * _size.Z; // default | ||
1309 | float tmp; | ||
1310 | |||
1311 | float returnMass = 0; | ||
1312 | float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; | ||
1313 | float hollowVolume = hollowAmount * hollowAmount; | ||
1314 | |||
1315 | switch (BaseShape.ProfileShape) | ||
1316 | { | ||
1317 | case ProfileShape.Square: | ||
1318 | // default box | ||
1319 | |||
1320 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | ||
1321 | { | ||
1322 | if (hollowAmount > 0.0) | ||
1323 | { | ||
1324 | switch (BaseShape.HollowShape) | ||
1325 | { | ||
1326 | case HollowShape.Square: | ||
1327 | case HollowShape.Same: | ||
1328 | break; | ||
1329 | |||
1330 | case HollowShape.Circle: | ||
1331 | |||
1332 | hollowVolume *= 0.78539816339f; | ||
1333 | break; | ||
1334 | |||
1335 | case HollowShape.Triangle: | ||
1336 | |||
1337 | hollowVolume *= (0.5f * .5f); | ||
1338 | break; | ||
1339 | |||
1340 | default: | ||
1341 | hollowVolume = 0; | ||
1342 | break; | ||
1343 | } | ||
1344 | volume *= (1.0f - hollowVolume); | ||
1345 | } | ||
1346 | } | ||
1347 | |||
1348 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | ||
1349 | { | ||
1350 | //a tube | ||
1351 | |||
1352 | volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); | ||
1353 | tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); | ||
1354 | volume -= volume*tmp*tmp; | ||
1355 | |||
1356 | if (hollowAmount > 0.0) | ||
1357 | { | ||
1358 | hollowVolume *= hollowAmount; | ||
1359 | |||
1360 | switch (BaseShape.HollowShape) | ||
1361 | { | ||
1362 | case HollowShape.Square: | ||
1363 | case HollowShape.Same: | ||
1364 | break; | ||
1365 | |||
1366 | case HollowShape.Circle: | ||
1367 | hollowVolume *= 0.78539816339f;; | ||
1368 | break; | ||
1369 | |||
1370 | case HollowShape.Triangle: | ||
1371 | hollowVolume *= 0.5f * 0.5f; | ||
1372 | break; | ||
1373 | default: | ||
1374 | hollowVolume = 0; | ||
1375 | break; | ||
1376 | } | ||
1377 | volume *= (1.0f - hollowVolume); | ||
1378 | } | ||
1379 | } | ||
1380 | |||
1381 | break; | ||
1382 | |||
1383 | case ProfileShape.Circle: | ||
1384 | |||
1385 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | ||
1386 | { | ||
1387 | volume *= 0.78539816339f; // elipse base | ||
1388 | |||
1389 | if (hollowAmount > 0.0) | ||
1390 | { | ||
1391 | switch (BaseShape.HollowShape) | ||
1392 | { | ||
1393 | case HollowShape.Same: | ||
1394 | case HollowShape.Circle: | ||
1395 | break; | ||
1396 | |||
1397 | case HollowShape.Square: | ||
1398 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
1399 | break; | ||
1400 | |||
1401 | case HollowShape.Triangle: | ||
1402 | hollowVolume *= .5f * 1.27323954473516f; | ||
1403 | break; | ||
1404 | |||
1405 | default: | ||
1406 | hollowVolume = 0; | ||
1407 | break; | ||
1408 | } | ||
1409 | volume *= (1.0f - hollowVolume); | ||
1410 | } | ||
1411 | } | ||
1412 | |||
1413 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | ||
1414 | { | ||
1415 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); | ||
1416 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); | ||
1417 | volume *= (1.0f - tmp * tmp); | ||
1418 | |||
1419 | if (hollowAmount > 0.0) | ||
1420 | { | ||
1421 | |||
1422 | // calculate the hollow volume by it's shape compared to the prim shape | ||
1423 | hollowVolume *= hollowAmount; | ||
1424 | |||
1425 | switch (BaseShape.HollowShape) | ||
1426 | { | ||
1427 | case HollowShape.Same: | ||
1428 | case HollowShape.Circle: | ||
1429 | break; | ||
1430 | |||
1431 | case HollowShape.Square: | ||
1432 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
1433 | break; | ||
1434 | |||
1435 | case HollowShape.Triangle: | ||
1436 | hollowVolume *= .5f * 1.27323954473516f; | ||
1437 | break; | ||
1438 | |||
1439 | default: | ||
1440 | hollowVolume = 0; | ||
1441 | break; | ||
1442 | } | ||
1443 | volume *= (1.0f - hollowVolume); | ||
1444 | } | ||
1445 | } | ||
1446 | break; | ||
1447 | |||
1448 | case ProfileShape.HalfCircle: | ||
1449 | if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | ||
1450 | { | ||
1451 | volume *= 0.52359877559829887307710723054658f; | ||
1452 | } | ||
1453 | break; | ||
1454 | |||
1455 | case ProfileShape.EquilateralTriangle: | ||
1456 | |||
1457 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | ||
1458 | { | ||
1459 | volume *= 0.32475953f; | ||
1460 | |||
1461 | if (hollowAmount > 0.0) | ||
1462 | { | ||
1463 | |||
1464 | // calculate the hollow volume by it's shape compared to the prim shape | ||
1465 | switch (BaseShape.HollowShape) | ||
1466 | { | ||
1467 | case HollowShape.Same: | ||
1468 | case HollowShape.Triangle: | ||
1469 | hollowVolume *= .25f; | ||
1470 | break; | ||
1471 | |||
1472 | case HollowShape.Square: | ||
1473 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
1474 | break; | ||
1475 | |||
1476 | case HollowShape.Circle: | ||
1477 | // Hollow shape is a perfect cyllinder in respect to the cube's scale | ||
1478 | // Cyllinder hollow volume calculation | ||
1479 | |||
1480 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
1481 | break; | ||
1482 | |||
1483 | default: | ||
1484 | hollowVolume = 0; | ||
1485 | break; | ||
1486 | } | ||
1487 | volume *= (1.0f - hollowVolume); | ||
1488 | } | ||
1489 | } | ||
1490 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | ||
1491 | { | ||
1492 | volume *= 0.32475953f; | ||
1493 | volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); | ||
1494 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); | ||
1495 | volume *= (1.0f - tmp * tmp); | ||
1496 | |||
1497 | if (hollowAmount > 0.0) | ||
1498 | { | ||
1499 | |||
1500 | hollowVolume *= hollowAmount; | ||
1501 | |||
1502 | switch (BaseShape.HollowShape) | ||
1503 | { | ||
1504 | case HollowShape.Same: | ||
1505 | case HollowShape.Triangle: | ||
1506 | hollowVolume *= .25f; | ||
1507 | break; | ||
1508 | |||
1509 | case HollowShape.Square: | ||
1510 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
1511 | break; | ||
1512 | |||
1513 | case HollowShape.Circle: | ||
1514 | |||
1515 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
1516 | break; | ||
1517 | |||
1518 | default: | ||
1519 | hollowVolume = 0; | ||
1520 | break; | ||
1521 | } | ||
1522 | volume *= (1.0f - hollowVolume); | ||
1523 | } | ||
1524 | } | ||
1525 | break; | ||
1526 | |||
1527 | default: | ||
1528 | break; | ||
1529 | } | ||
1530 | |||
1531 | |||
1532 | |||
1533 | float taperX1; | ||
1534 | float taperY1; | ||
1535 | float taperX; | ||
1536 | float taperY; | ||
1537 | float pathBegin; | ||
1538 | float pathEnd; | ||
1539 | float profileBegin; | ||
1540 | float profileEnd; | ||
1541 | |||
1542 | if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) | ||
1543 | { | ||
1544 | taperX1 = BaseShape.PathScaleX * 0.01f; | ||
1545 | if (taperX1 > 1.0f) | ||
1546 | taperX1 = 2.0f - taperX1; | ||
1547 | taperX = 1.0f - taperX1; | ||
1548 | |||
1549 | taperY1 = BaseShape.PathScaleY * 0.01f; | ||
1550 | if (taperY1 > 1.0f) | ||
1551 | taperY1 = 2.0f - taperY1; | ||
1552 | taperY = 1.0f - taperY1; | ||
1553 | } | ||
1554 | else | ||
1555 | { | ||
1556 | taperX = BaseShape.PathTaperX * 0.01f; | ||
1557 | if (taperX < 0.0f) | ||
1558 | taperX = -taperX; | ||
1559 | taperX1 = 1.0f - taperX; | ||
1560 | |||
1561 | taperY = BaseShape.PathTaperY * 0.01f; | ||
1562 | if (taperY < 0.0f) | ||
1563 | taperY = -taperY; | ||
1564 | taperY1 = 1.0f - taperY; | ||
1565 | |||
1566 | } | ||
1567 | |||
1568 | |||
1569 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | ||
1570 | |||
1571 | pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; | ||
1572 | pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; | ||
1573 | volume *= (pathEnd - pathBegin); | ||
1574 | |||
1575 | // this is crude aproximation | ||
1576 | profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; | ||
1577 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; | ||
1578 | volume *= (profileEnd - profileBegin); | ||
1579 | |||
1580 | returnMass = Density * BSParam.DensityScaleFactor * volume; | ||
1581 | |||
1582 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); | ||
1583 | // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); | ||
1584 | DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}", | ||
1585 | LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size); | ||
1586 | |||
1587 | return returnMass; | ||
1588 | }// end CalculateMass | ||
1589 | #endregion Mass Calculation | ||
1590 | |||
1591 | // Rebuild the geometry and object. | ||
1592 | // This is called when the shape changes so we need to recreate the mesh/hull. | ||
1593 | // Called at taint-time!!! | ||
1594 | public void CreateGeomAndObject(bool forceRebuild) | ||
1595 | { | ||
1596 | // Create the correct physical representation for this type of object. | ||
1597 | // Updates base.PhysBody and base.PhysShape with the new information. | ||
1598 | // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. | ||
1599 | PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) | ||
1600 | { | ||
1601 | // Called if the current prim body is about to be destroyed. | ||
1602 | // Remove all the physical dependencies on the old body. | ||
1603 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) | ||
1604 | // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. | ||
1605 | RemoveDependencies(); | ||
1606 | }); | ||
1607 | |||
1608 | // Make sure the properties are set on the new object | ||
1609 | UpdatePhysicalParameters(); | ||
1610 | return; | ||
1611 | } | ||
1612 | |||
1613 | // Called at taint-time | ||
1614 | protected virtual void RemoveDependencies() | ||
1615 | { | ||
1616 | PhysicalActors.RemoveDependencies(); | ||
1617 | } | ||
1618 | |||
1619 | #region Extension | ||
1620 | public override object Extension(string pFunct, params object[] pParams) | ||
1621 | { | ||
1622 | DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct); | ||
1623 | object ret = null; | ||
1624 | switch (pFunct) | ||
1625 | { | ||
1626 | case ExtendedPhysics.PhysFunctAxisLockLimits: | ||
1627 | ret = SetAxisLockLimitsExtension(pParams); | ||
1628 | break; | ||
1629 | default: | ||
1630 | ret = base.Extension(pFunct, pParams); | ||
1631 | break; | ||
1632 | } | ||
1633 | return ret; | ||
1634 | } | ||
1635 | |||
1636 | private void InitializeAxisActor() | ||
1637 | { | ||
1638 | EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree, | ||
1639 | LockedAxisActorName, delegate() | ||
1640 | { | ||
1641 | return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); | ||
1642 | }); | ||
1643 | |||
1644 | // Update parameters so the new actor's Refresh() action is called at the right time. | ||
1645 | PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate() | ||
1646 | { | ||
1647 | UpdatePhysicalParameters(); | ||
1648 | }); | ||
1649 | } | ||
1650 | |||
1651 | // Passed an array of an array of parameters, set the axis locking. | ||
1652 | // This expects an int (PHYS_AXIS_*) followed by none or two limit floats | ||
1653 | // followed by another int and floats, etc. | ||
1654 | private object SetAxisLockLimitsExtension(object[] pParams) | ||
1655 | { | ||
1656 | DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0)); | ||
1657 | object ret = null; | ||
1658 | try | ||
1659 | { | ||
1660 | if (pParams.GetLength(0) > 1) | ||
1661 | { | ||
1662 | int index = 2; | ||
1663 | while (index < pParams.GetLength(0)) | ||
1664 | { | ||
1665 | var funct = pParams[index]; | ||
1666 | DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index); | ||
1667 | if (funct is Int32 || funct is Int64) | ||
1668 | { | ||
1669 | switch ((int)funct) | ||
1670 | { | ||
1671 | // Those that take no parameters | ||
1672 | case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: | ||
1673 | case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: | ||
1674 | case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: | ||
1675 | case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: | ||
1676 | case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: | ||
1677 | case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: | ||
1678 | case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: | ||
1679 | case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: | ||
1680 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: | ||
1681 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: | ||
1682 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: | ||
1683 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: | ||
1684 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: | ||
1685 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: | ||
1686 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: | ||
1687 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: | ||
1688 | case ExtendedPhysics.PHYS_AXIS_UNLOCK: | ||
1689 | ApplyAxisLimits((int)funct, 0f, 0f); | ||
1690 | index += 1; | ||
1691 | break; | ||
1692 | // Those that take two parameters (the limits) | ||
1693 | case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: | ||
1694 | case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: | ||
1695 | case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: | ||
1696 | case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: | ||
1697 | case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: | ||
1698 | case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: | ||
1699 | ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]); | ||
1700 | index += 3; | ||
1701 | break; | ||
1702 | default: | ||
1703 | m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct); | ||
1704 | index += 1; | ||
1705 | break; | ||
1706 | } | ||
1707 | } | ||
1708 | } | ||
1709 | InitializeAxisActor(); | ||
1710 | ret = (object)index; | ||
1711 | } | ||
1712 | } | ||
1713 | catch (Exception e) | ||
1714 | { | ||
1715 | m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e); | ||
1716 | ret = null; | ||
1717 | } | ||
1718 | return ret; // not implemented yet | ||
1719 | } | ||
1720 | |||
1721 | // Set the locking parameters. | ||
1722 | // If an axis is locked, the limits for the axis are set to zero, | ||
1723 | // If the axis is being constrained, the high and low value are passed and set. | ||
1724 | // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range. | ||
1725 | protected void ApplyAxisLimits(int funct, float low, float high) | ||
1726 | { | ||
1727 | DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high); | ||
1728 | float linearMax = 23000f; | ||
1729 | float angularMax = (float)Math.PI; | ||
1730 | |||
1731 | switch (funct) | ||
1732 | { | ||
1733 | case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: | ||
1734 | this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); | ||
1735 | this.LockedLinearAxisLow = OMV.Vector3.Zero; | ||
1736 | this.LockedLinearAxisHigh = OMV.Vector3.Zero; | ||
1737 | break; | ||
1738 | case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: | ||
1739 | this.LockedLinearAxis.X = LockedAxis; | ||
1740 | this.LockedLinearAxisLow.X = 0f; | ||
1741 | this.LockedLinearAxisHigh.X = 0f; | ||
1742 | break; | ||
1743 | case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: | ||
1744 | this.LockedLinearAxis.X = LockedAxis; | ||
1745 | this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax); | ||
1746 | this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax); | ||
1747 | break; | ||
1748 | case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: | ||
1749 | this.LockedLinearAxis.Y = LockedAxis; | ||
1750 | this.LockedLinearAxisLow.Y = 0f; | ||
1751 | this.LockedLinearAxisHigh.Y = 0f; | ||
1752 | break; | ||
1753 | case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: | ||
1754 | this.LockedLinearAxis.Y = LockedAxis; | ||
1755 | this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax); | ||
1756 | this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax); | ||
1757 | break; | ||
1758 | case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: | ||
1759 | this.LockedLinearAxis.Z = LockedAxis; | ||
1760 | this.LockedLinearAxisLow.Z = 0f; | ||
1761 | this.LockedLinearAxisHigh.Z = 0f; | ||
1762 | break; | ||
1763 | case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: | ||
1764 | this.LockedLinearAxis.Z = LockedAxis; | ||
1765 | this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax); | ||
1766 | this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax); | ||
1767 | break; | ||
1768 | case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: | ||
1769 | this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); | ||
1770 | this.LockedAngularAxisLow = OMV.Vector3.Zero; | ||
1771 | this.LockedAngularAxisHigh = OMV.Vector3.Zero; | ||
1772 | break; | ||
1773 | case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: | ||
1774 | this.LockedAngularAxis.X = LockedAxis; | ||
1775 | this.LockedAngularAxisLow.X = 0; | ||
1776 | this.LockedAngularAxisHigh.X = 0; | ||
1777 | break; | ||
1778 | case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: | ||
1779 | this.LockedAngularAxis.X = LockedAxis; | ||
1780 | this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax); | ||
1781 | this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax); | ||
1782 | break; | ||
1783 | case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: | ||
1784 | this.LockedAngularAxis.Y = LockedAxis; | ||
1785 | this.LockedAngularAxisLow.Y = 0; | ||
1786 | this.LockedAngularAxisHigh.Y = 0; | ||
1787 | break; | ||
1788 | case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: | ||
1789 | this.LockedAngularAxis.Y = LockedAxis; | ||
1790 | this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax); | ||
1791 | this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax); | ||
1792 | break; | ||
1793 | case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: | ||
1794 | this.LockedAngularAxis.Z = LockedAxis; | ||
1795 | this.LockedAngularAxisLow.Z = 0; | ||
1796 | this.LockedAngularAxisHigh.Z = 0; | ||
1797 | break; | ||
1798 | case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: | ||
1799 | this.LockedAngularAxis.Z = LockedAxis; | ||
1800 | this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax); | ||
1801 | this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax); | ||
1802 | break; | ||
1803 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: | ||
1804 | this.LockedLinearAxis = LockedAxisFree; | ||
1805 | this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax); | ||
1806 | this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax); | ||
1807 | break; | ||
1808 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: | ||
1809 | this.LockedLinearAxis.X = FreeAxis; | ||
1810 | this.LockedLinearAxisLow.X = -linearMax; | ||
1811 | this.LockedLinearAxisHigh.X = linearMax; | ||
1812 | break; | ||
1813 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: | ||
1814 | this.LockedLinearAxis.Y = FreeAxis; | ||
1815 | this.LockedLinearAxisLow.Y = -linearMax; | ||
1816 | this.LockedLinearAxisHigh.Y = linearMax; | ||
1817 | break; | ||
1818 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: | ||
1819 | this.LockedLinearAxis.Z = FreeAxis; | ||
1820 | this.LockedLinearAxisLow.Z = -linearMax; | ||
1821 | this.LockedLinearAxisHigh.Z = linearMax; | ||
1822 | break; | ||
1823 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: | ||
1824 | this.LockedAngularAxis = LockedAxisFree; | ||
1825 | this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax); | ||
1826 | this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax); | ||
1827 | break; | ||
1828 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: | ||
1829 | this.LockedAngularAxis.X = FreeAxis; | ||
1830 | this.LockedAngularAxisLow.X = -angularMax; | ||
1831 | this.LockedAngularAxisHigh.X = angularMax; | ||
1832 | break; | ||
1833 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: | ||
1834 | this.LockedAngularAxis.Y = FreeAxis; | ||
1835 | this.LockedAngularAxisLow.Y = -angularMax; | ||
1836 | this.LockedAngularAxisHigh.Y = angularMax; | ||
1837 | break; | ||
1838 | case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: | ||
1839 | this.LockedAngularAxis.Z = FreeAxis; | ||
1840 | this.LockedAngularAxisLow.Z = -angularMax; | ||
1841 | this.LockedAngularAxisHigh.Z = angularMax; | ||
1842 | break; | ||
1843 | case ExtendedPhysics.PHYS_AXIS_UNLOCK: | ||
1844 | ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f); | ||
1845 | ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); | ||
1846 | break; | ||
1847 | default: | ||
1848 | break; | ||
1849 | } | ||
1850 | return; | ||
1851 | } | ||
1852 | #endregion // Extension | ||
1853 | |||
1854 | // The physics engine says that properties have updated. Update same and inform | ||
1855 | // the world that things have changed. | ||
1856 | // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims. | ||
1857 | // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position. | ||
1858 | public override void UpdateProperties(EntityProperties entprop) | ||
1859 | { | ||
1860 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. | ||
1861 | TriggerPreUpdatePropertyAction(ref entprop); | ||
1862 | |||
1863 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG | ||
1864 | |||
1865 | // Assign directly to the local variables so the normal set actions do not happen | ||
1866 | RawPosition = entprop.Position; | ||
1867 | RawOrientation = entprop.Rotation; | ||
1868 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be | ||
1869 | // very sensitive to velocity changes. | ||
1870 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) | ||
1871 | RawVelocity = entprop.Velocity; | ||
1872 | _acceleration = entprop.Acceleration; | ||
1873 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1874 | |||
1875 | // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG | ||
1876 | |||
1877 | // The sanity check can change the velocity and/or position. | ||
1878 | if (PositionSanityCheck(true /* inTaintTime */ )) | ||
1879 | { | ||
1880 | entprop.Position = RawPosition; | ||
1881 | entprop.Velocity = RawVelocity; | ||
1882 | entprop.RotationalVelocity = _rotationalVelocity; | ||
1883 | entprop.Acceleration = _acceleration; | ||
1884 | } | ||
1885 | |||
1886 | OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG | ||
1887 | DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); | ||
1888 | |||
1889 | // remember the current and last set values | ||
1890 | LastEntityProperties = CurrentEntityProperties; | ||
1891 | CurrentEntityProperties = entprop; | ||
1892 | |||
1893 | PhysScene.PostUpdate(this); | ||
1894 | } | ||
1895 | } | ||
1896 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs new file mode 100755 index 0000000..2eb1440 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs | |||
@@ -0,0 +1,182 @@ | |||
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 OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | using OMV = OpenMetaverse; | ||
37 | |||
38 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
39 | { | ||
40 | public class BSPrimDisplaced : BSPrim | ||
41 | { | ||
42 | // The purpose of this subclass is to do any mapping between what the simulator thinks | ||
43 | // the prim position and orientation is and what the physical position/orientation. | ||
44 | // This difference happens because Bullet assumes the center-of-mass is the <0,0,0> | ||
45 | // of the prim/linkset. The simulator, on the other hand, tracks the location of | ||
46 | // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere | ||
47 | // but the origin of the root prim, the physical origin is displaced from the simulator origin. | ||
48 | // | ||
49 | // This routine works by capturing ForcePosition and | ||
50 | // adjusting the simulator values (being set) into the physical values. | ||
51 | // The conversion is also done in the opposite direction (physical origin -> simulator origin). | ||
52 | // | ||
53 | // The updateParameter call is also captured and the values from the physics engine | ||
54 | // are converted into simulator origin values before being passed to the base | ||
55 | // class. | ||
56 | |||
57 | // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass. | ||
58 | public virtual OMV.Vector3 PositionDisplacement { get; set; } | ||
59 | |||
60 | public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
61 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
62 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | ||
63 | { | ||
64 | ClearDisplacement(); | ||
65 | } | ||
66 | |||
67 | // Clears any center-of-mass displacement introduced by linksets, etc. | ||
68 | // Does not clear the displacement set by the user. | ||
69 | public void ClearDisplacement() | ||
70 | { | ||
71 | if (UserSetCenterOfMassDisplacement.HasValue) | ||
72 | PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement; | ||
73 | else | ||
74 | PositionDisplacement = OMV.Vector3.Zero; | ||
75 | } | ||
76 | |||
77 | // Set this sets and computes the displacement from the passed prim to the center-of-mass. | ||
78 | // A user set value for center-of-mass overrides whatever might be passed in here. | ||
79 | // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). | ||
80 | // Returns the relative offset from the root position to the center-of-mass. | ||
81 | // Called at taint time. | ||
82 | public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) | ||
83 | { | ||
84 | PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement"); | ||
85 | Vector3 comDisp; | ||
86 | if (UserSetCenterOfMassDisplacement.HasValue) | ||
87 | comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; | ||
88 | else | ||
89 | comDisp = centerOfMassDisplacement; | ||
90 | |||
91 | // Eliminate any jitter caused be very slight differences in masses and positions | ||
92 | if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) ) | ||
93 | comDisp = Vector3.Zero; | ||
94 | |||
95 | DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", | ||
96 | LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); | ||
97 | if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) ) | ||
98 | { | ||
99 | // Displacement setting is changing. | ||
100 | // The relationship between the physical object and simulated object must be aligned. | ||
101 | PositionDisplacement = comDisp; | ||
102 | this.ForcePosition = RawPosition; | ||
103 | } | ||
104 | |||
105 | return PositionDisplacement; | ||
106 | } | ||
107 | |||
108 | // 'ForcePosition' is the one way to set the physical position of the body in the physics engine. | ||
109 | // Displace the simulator idea of position (center of root prim) to the physical position. | ||
110 | public override Vector3 ForcePosition | ||
111 | { | ||
112 | get { | ||
113 | OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody); | ||
114 | if (PositionDisplacement != OMV.Vector3.Zero) | ||
115 | { | ||
116 | // If there is some displacement, return the physical position (center-of-mass) | ||
117 | // location minus the displacement to give the center of the root prim. | ||
118 | OMV.Vector3 displacement = PositionDisplacement * ForceOrientation; | ||
119 | DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}", | ||
120 | LocalID, physPosition, displacement, physPosition - displacement); | ||
121 | physPosition -= displacement; | ||
122 | } | ||
123 | RawPosition = physPosition; | ||
124 | return physPosition; | ||
125 | } | ||
126 | set | ||
127 | { | ||
128 | if (PositionDisplacement != OMV.Vector3.Zero) | ||
129 | { | ||
130 | // This value is the simulator's idea of where the prim is: the center of the root prim | ||
131 | RawPosition = value; | ||
132 | |||
133 | // Move the passed root prim postion to the center-of-mass position and set in the physics engine. | ||
134 | OMV.Vector3 displacement = PositionDisplacement * RawOrientation; | ||
135 | OMV.Vector3 displacedPos = RawPosition + displacement; | ||
136 | DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}", | ||
137 | LocalID, RawPosition, displacement, displacedPos); | ||
138 | if (PhysBody.HasPhysicalBody) | ||
139 | { | ||
140 | PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation); | ||
141 | ActivateIfPhysical(false); | ||
142 | } | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | base.ForcePosition = value; | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | // These are also overridden by BSPrimLinkable if the prim can be part of a linkset | ||
152 | public override OMV.Vector3 CenterOfMass | ||
153 | { | ||
154 | get { return RawPosition; } | ||
155 | } | ||
156 | |||
157 | public override OMV.Vector3 GeometricCenter | ||
158 | { | ||
159 | get { return RawPosition; } | ||
160 | } | ||
161 | |||
162 | public override void UpdateProperties(EntityProperties entprop) | ||
163 | { | ||
164 | // Undo any center-of-mass displacement that might have been done. | ||
165 | if (PositionDisplacement != OMV.Vector3.Zero) | ||
166 | { | ||
167 | // The origional shape was offset from 'zero' by PositionDisplacement. | ||
168 | // These physical location must be back converted to be centered around the displaced | ||
169 | // root shape. | ||
170 | |||
171 | // Move the returned center-of-mass location to the root prim location. | ||
172 | OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation; | ||
173 | OMV.Vector3 displacedPos = entprop.Position - displacement; | ||
174 | DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}", | ||
175 | LocalID, entprop.Position, displacement, displacedPos); | ||
176 | entprop.Position = displacedPos; | ||
177 | } | ||
178 | |||
179 | base.UpdateProperties(entprop); | ||
180 | } | ||
181 | } | ||
182 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs new file mode 100755 index 0000000..430d645 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs | |||
@@ -0,0 +1,350 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Linq; | ||
30 | using System.Text; | ||
31 | |||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.OptionalModules.Scripting; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSPrimLinkable : BSPrimDisplaced | ||
40 | { | ||
41 | // The purpose of this subclass is to add linkset functionality to the prim. This overrides | ||
42 | // operations necessary for keeping the linkset created and, additionally, this | ||
43 | // calls the linkset implementation for its creation and management. | ||
44 | |||
45 | #pragma warning disable 414 | ||
46 | private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]"; | ||
47 | #pragma warning restore 414 | ||
48 | |||
49 | // This adds the overrides for link() and delink() so the prim is linkable. | ||
50 | |||
51 | public BSLinkset Linkset { get; set; } | ||
52 | // The index of this child prim. | ||
53 | public int LinksetChildIndex { get; set; } | ||
54 | |||
55 | public BSLinkset.LinksetImplementation LinksetType { get; set; } | ||
56 | |||
57 | public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
58 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
59 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | ||
60 | { | ||
61 | // Default linkset implementation for this prim | ||
62 | LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation; | ||
63 | |||
64 | Linkset = BSLinkset.Factory(PhysScene, this); | ||
65 | |||
66 | Linkset.Refresh(this); | ||
67 | } | ||
68 | |||
69 | public override void Destroy() | ||
70 | { | ||
71 | Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */); | ||
72 | base.Destroy(); | ||
73 | } | ||
74 | |||
75 | public override void link(Manager.PhysicsActor obj) | ||
76 | { | ||
77 | BSPrimLinkable parent = obj as BSPrimLinkable; | ||
78 | if (parent != null) | ||
79 | { | ||
80 | BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG | ||
81 | int childrenBefore = Linkset.NumberOfChildren; // DEBUG | ||
82 | |||
83 | Linkset = parent.Linkset.AddMeToLinkset(this); | ||
84 | |||
85 | DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | ||
86 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
87 | } | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | public override void delink() | ||
92 | { | ||
93 | // TODO: decide if this parent checking needs to happen at taint time | ||
94 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | ||
95 | |||
96 | BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG | ||
97 | int childrenBefore = Linkset.NumberOfChildren; // DEBUG | ||
98 | |||
99 | Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/); | ||
100 | |||
101 | DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | ||
102 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | // When simulator changes position, this might be moving a child of the linkset. | ||
107 | public override OMV.Vector3 Position | ||
108 | { | ||
109 | get { return base.Position; } | ||
110 | set | ||
111 | { | ||
112 | base.Position = value; | ||
113 | PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate() | ||
114 | { | ||
115 | Linkset.UpdateProperties(UpdatedProperties.Position, this); | ||
116 | }); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | // When simulator changes orientation, this might be moving a child of the linkset. | ||
121 | public override OMV.Quaternion Orientation | ||
122 | { | ||
123 | get { return base.Orientation; } | ||
124 | set | ||
125 | { | ||
126 | base.Orientation = value; | ||
127 | PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate() | ||
128 | { | ||
129 | Linkset.UpdateProperties(UpdatedProperties.Orientation, this); | ||
130 | }); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | public override float TotalMass | ||
135 | { | ||
136 | get { return Linkset.LinksetMass; } | ||
137 | } | ||
138 | |||
139 | public override OMV.Vector3 CenterOfMass | ||
140 | { | ||
141 | get { return Linkset.CenterOfMass; } | ||
142 | } | ||
143 | |||
144 | public override OMV.Vector3 GeometricCenter | ||
145 | { | ||
146 | get { return Linkset.GeometricCenter; } | ||
147 | } | ||
148 | |||
149 | // Refresh the linkset structure and parameters when the prim's physical parameters are changed. | ||
150 | public override void UpdatePhysicalParameters() | ||
151 | { | ||
152 | base.UpdatePhysicalParameters(); | ||
153 | // Recompute any linkset parameters. | ||
154 | // When going from non-physical to physical, this re-enables the constraints that | ||
155 | // had been automatically disabled when the mass was set to zero. | ||
156 | // For compound based linksets, this enables and disables interactions of the children. | ||
157 | if (Linkset != null) // null can happen during initialization | ||
158 | Linkset.Refresh(this); | ||
159 | } | ||
160 | |||
161 | // When the prim is made dynamic or static, the linkset needs to change. | ||
162 | protected override void MakeDynamic(bool makeStatic) | ||
163 | { | ||
164 | base.MakeDynamic(makeStatic); | ||
165 | if (Linkset != null) // null can happen during initialization | ||
166 | { | ||
167 | if (makeStatic) | ||
168 | Linkset.MakeStatic(this); | ||
169 | else | ||
170 | Linkset.MakeDynamic(this); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | // Body is being taken apart. Remove physical dependencies and schedule a rebuild. | ||
175 | protected override void RemoveDependencies() | ||
176 | { | ||
177 | Linkset.RemoveDependencies(this); | ||
178 | base.RemoveDependencies(); | ||
179 | } | ||
180 | |||
181 | // Called after a simulation step for the changes in physical object properties. | ||
182 | // Do any filtering/modification needed for linksets. | ||
183 | public override void UpdateProperties(EntityProperties entprop) | ||
184 | { | ||
185 | if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this)) | ||
186 | { | ||
187 | // Properties are only updated for the roots of a linkset. | ||
188 | // TODO: this will have to change when linksets are articulated. | ||
189 | base.UpdateProperties(entprop); | ||
190 | } | ||
191 | /* | ||
192 | else | ||
193 | { | ||
194 | // For debugging, report the movement of children | ||
195 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
196 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
197 | entprop.Acceleration, entprop.RotationalVelocity); | ||
198 | } | ||
199 | */ | ||
200 | // The linkset might like to know about changing locations | ||
201 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); | ||
202 | } | ||
203 | |||
204 | // Called after a simulation step to post a collision with this object. | ||
205 | // This returns 'true' if the collision has been queued and the SendCollisions call must | ||
206 | // be made at the end of the simulation step. | ||
207 | public override bool Collide(uint collidingWith, BSPhysObject collidee, | ||
208 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
209 | { | ||
210 | bool ret = false; | ||
211 | // Ask the linkset if it wants to handle the collision | ||
212 | if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth)) | ||
213 | { | ||
214 | // The linkset didn't handle it so pass the collision through normal processing | ||
215 | ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); | ||
216 | } | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | // A linkset reports any collision on any part of the linkset. | ||
221 | public long SomeCollisionSimulationStep = 0; | ||
222 | public override bool HasSomeCollision | ||
223 | { | ||
224 | get | ||
225 | { | ||
226 | return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding; | ||
227 | } | ||
228 | set | ||
229 | { | ||
230 | if (value) | ||
231 | SomeCollisionSimulationStep = PhysScene.SimulationStep; | ||
232 | else | ||
233 | SomeCollisionSimulationStep = 0; | ||
234 | |||
235 | base.HasSomeCollision = value; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | // Convert the existing linkset of this prim into a new type. | ||
240 | public bool ConvertLinkset(BSLinkset.LinksetImplementation newType) | ||
241 | { | ||
242 | bool ret = false; | ||
243 | if (LinksetType != newType) | ||
244 | { | ||
245 | DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType); | ||
246 | |||
247 | // Set the implementation type first so the call to BSLinkset.Factory gets the new type. | ||
248 | this.LinksetType = newType; | ||
249 | |||
250 | BSLinkset oldLinkset = this.Linkset; | ||
251 | BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this); | ||
252 | |||
253 | this.Linkset = newLinkset; | ||
254 | |||
255 | // Pick up any physical dependencies this linkset might have in the physics engine. | ||
256 | oldLinkset.RemoveDependencies(this); | ||
257 | |||
258 | // Create a list of the children (mainly because can't interate through a list that's changing) | ||
259 | List<BSPrimLinkable> children = new List<BSPrimLinkable>(); | ||
260 | oldLinkset.ForEachMember((child) => | ||
261 | { | ||
262 | if (!oldLinkset.IsRoot(child)) | ||
263 | children.Add(child); | ||
264 | return false; // 'false' says to continue to next member | ||
265 | }); | ||
266 | |||
267 | // Remove the children from the old linkset and add to the new (will be a new instance from the factory) | ||
268 | foreach (BSPrimLinkable child in children) | ||
269 | { | ||
270 | oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/); | ||
271 | } | ||
272 | foreach (BSPrimLinkable child in children) | ||
273 | { | ||
274 | newLinkset.AddMeToLinkset(child); | ||
275 | child.Linkset = newLinkset; | ||
276 | } | ||
277 | |||
278 | // Force the shape and linkset to get reconstructed | ||
279 | newLinkset.Refresh(this); | ||
280 | this.ForceBodyShapeRebuild(true /* inTaintTime */); | ||
281 | } | ||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | #region Extension | ||
286 | public override object Extension(string pFunct, params object[] pParams) | ||
287 | { | ||
288 | DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length); | ||
289 | object ret = null; | ||
290 | switch (pFunct) | ||
291 | { | ||
292 | // physGetLinksetType(); | ||
293 | // pParams = [ BSPhysObject root, null ] | ||
294 | case ExtendedPhysics.PhysFunctGetLinksetType: | ||
295 | { | ||
296 | ret = (object)LinksetType; | ||
297 | DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret); | ||
298 | break; | ||
299 | } | ||
300 | // physSetLinksetType(type); | ||
301 | // pParams = [ BSPhysObject root, null, integer type ] | ||
302 | case ExtendedPhysics.PhysFunctSetLinksetType: | ||
303 | { | ||
304 | if (pParams.Length > 2) | ||
305 | { | ||
306 | BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2]; | ||
307 | if (Linkset.IsRoot(this)) | ||
308 | { | ||
309 | PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate() | ||
310 | { | ||
311 | // Cause the linkset type to change | ||
312 | DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}", | ||
313 | LocalID, Linkset.LinksetImpl, linksetType); | ||
314 | ConvertLinkset(linksetType); | ||
315 | }); | ||
316 | } | ||
317 | ret = (object)(int)linksetType; | ||
318 | } | ||
319 | break; | ||
320 | } | ||
321 | // physChangeLinkType(linknum, typeCode); | ||
322 | // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] | ||
323 | case ExtendedPhysics.PhysFunctChangeLinkType: | ||
324 | { | ||
325 | ret = Linkset.Extension(pFunct, pParams); | ||
326 | break; | ||
327 | } | ||
328 | // physGetLinkType(linknum); | ||
329 | // pParams = [ BSPhysObject root, BSPhysObject child ] | ||
330 | case ExtendedPhysics.PhysFunctGetLinkType: | ||
331 | { | ||
332 | ret = Linkset.Extension(pFunct, pParams); | ||
333 | break; | ||
334 | } | ||
335 | // physChangeLinkParams(linknum, [code, value, code, value, ...]); | ||
336 | // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ] | ||
337 | case ExtendedPhysics.PhysFunctChangeLinkParams: | ||
338 | { | ||
339 | ret = Linkset.Extension(pFunct, pParams); | ||
340 | break; | ||
341 | } | ||
342 | default: | ||
343 | ret = base.Extension(pFunct, pParams); | ||
344 | break; | ||
345 | } | ||
346 | return ret; | ||
347 | } | ||
348 | #endregion // Extension | ||
349 | } | ||
350 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs new file mode 100644 index 0000000..8a19944 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs | |||
@@ -0,0 +1,1281 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Linq; | ||
30 | using System.Reflection; | ||
31 | using System.Runtime.InteropServices; | ||
32 | using System.Text; | ||
33 | using System.Threading; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Monitoring; | ||
36 | using OpenSim.Region.Framework; | ||
37 | using OpenSim.Region.CoreModules; | ||
38 | using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging; | ||
39 | using OpenSim.Region.Physics.Manager; | ||
40 | using Nini.Config; | ||
41 | using log4net; | ||
42 | using OpenMetaverse; | ||
43 | |||
44 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
45 | { | ||
46 | public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||
47 | { | ||
48 | internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | internal static readonly string LogHeader = "[BULLETS SCENE]"; | ||
50 | |||
51 | // The name of the region we're working for. | ||
52 | public string RegionName { get; private set; } | ||
53 | |||
54 | public string BulletSimVersion = "?"; | ||
55 | |||
56 | // The handle to the underlying managed or unmanaged version of Bullet being used. | ||
57 | public string BulletEngineName { get; private set; } | ||
58 | public BSAPITemplate PE; | ||
59 | |||
60 | // If the physics engine is running on a separate thread | ||
61 | public Thread m_physicsThread; | ||
62 | |||
63 | public Dictionary<uint, BSPhysObject> PhysObjects; | ||
64 | public BSShapeCollection Shapes; | ||
65 | |||
66 | // Keeping track of the objects with collisions so we can report begin and end of a collision | ||
67 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); | ||
68 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); | ||
69 | |||
70 | // All the collision processing is protected with this lock object | ||
71 | public Object CollisionLock = new Object(); | ||
72 | |||
73 | // Properties are updated here | ||
74 | public Object UpdateLock = new Object(); | ||
75 | public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
76 | |||
77 | // Keep track of all the avatars so we can send them a collision event | ||
78 | // every tick so OpenSim will update its animation. | ||
79 | private HashSet<BSPhysObject> AvatarsInScene = new HashSet<BSPhysObject>(); | ||
80 | private Object AvatarsInSceneLock = new Object(); | ||
81 | |||
82 | // let my minuions use my logger | ||
83 | public ILog Logger { get { return m_log; } } | ||
84 | |||
85 | public IMesher mesher; | ||
86 | public uint WorldID { get; private set; } | ||
87 | public BulletWorld World { get; private set; } | ||
88 | |||
89 | // All the constraints that have been allocated in this instance. | ||
90 | public BSConstraintCollection Constraints { get; private set; } | ||
91 | |||
92 | // Simulation parameters | ||
93 | //internal float m_physicsStepTime; // if running independently, the interval simulated by default | ||
94 | |||
95 | internal int m_maxSubSteps; | ||
96 | internal float m_fixedTimeStep; | ||
97 | |||
98 | internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc. | ||
99 | |||
100 | internal long m_simulationStep = 0; // The current simulation step. | ||
101 | public long SimulationStep { get { return m_simulationStep; } } | ||
102 | // A number to use for SimulationStep that is probably not any step value | ||
103 | // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step. | ||
104 | public static long NotASimulationStep = -1234; | ||
105 | |||
106 | internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() | ||
107 | |||
108 | internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to | ||
109 | |||
110 | // Physical objects can register for prestep or poststep events | ||
111 | public delegate void PreStepAction(float timeStep); | ||
112 | public delegate void PostStepAction(float timeStep); | ||
113 | public event PreStepAction BeforeStep; | ||
114 | public event PostStepAction AfterStep; | ||
115 | |||
116 | // A value of the time 'now' so all the collision and update routines do not have to get their own | ||
117 | // Set to 'now' just before all the prims and actors are called for collisions and updates | ||
118 | public int SimulationNowTime { get; private set; } | ||
119 | |||
120 | // True if initialized and ready to do simulation steps | ||
121 | private bool m_initialized = false; | ||
122 | |||
123 | // Flag which is true when processing taints. | ||
124 | // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. | ||
125 | public bool InTaintTime { get; private set; } | ||
126 | |||
127 | // Pinned memory used to pass step information between managed and unmanaged | ||
128 | internal int m_maxCollisionsPerFrame; | ||
129 | internal CollisionDesc[] m_collisionArray; | ||
130 | |||
131 | internal int m_maxUpdatesPerFrame; | ||
132 | internal EntityProperties[] m_updateArray; | ||
133 | |||
134 | /// <summary> | ||
135 | /// Used to control physics simulation timing if Bullet is running on its own thread. | ||
136 | /// </summary> | ||
137 | private ManualResetEvent m_updateWaitEvent; | ||
138 | |||
139 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | ||
140 | public const uint GROUNDPLANE_ID = 1; | ||
141 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | ||
142 | |||
143 | public float SimpleWaterLevel { get; set; } | ||
144 | public BSTerrainManager TerrainManager { get; private set; } | ||
145 | |||
146 | public ConfigurationParameters Params | ||
147 | { | ||
148 | get { return UnmanagedParams[0]; } | ||
149 | } | ||
150 | public Vector3 DefaultGravity | ||
151 | { | ||
152 | get { return new Vector3(0f, 0f, Params.gravity); } | ||
153 | } | ||
154 | // Just the Z value of the gravity | ||
155 | public float DefaultGravityZ | ||
156 | { | ||
157 | get { return Params.gravity; } | ||
158 | } | ||
159 | |||
160 | // When functions in the unmanaged code must be called, it is only | ||
161 | // done at a known time just before the simulation step. The taint | ||
162 | // system saves all these function calls and executes them in | ||
163 | // order before the simulation. | ||
164 | public delegate void TaintCallback(); | ||
165 | private struct TaintCallbackEntry | ||
166 | { | ||
167 | public String originator; | ||
168 | public String ident; | ||
169 | public TaintCallback callback; | ||
170 | public TaintCallbackEntry(string pIdent, TaintCallback pCallBack) | ||
171 | { | ||
172 | originator = BSScene.DetailLogZero; | ||
173 | ident = pIdent; | ||
174 | callback = pCallBack; | ||
175 | } | ||
176 | public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack) | ||
177 | { | ||
178 | originator = pOrigin; | ||
179 | ident = pIdent; | ||
180 | callback = pCallBack; | ||
181 | } | ||
182 | } | ||
183 | private Object _taintLock = new Object(); // lock for using the next object | ||
184 | private List<TaintCallbackEntry> _taintOperations; | ||
185 | private Dictionary<string, TaintCallbackEntry> _postTaintOperations; | ||
186 | private List<TaintCallbackEntry> _postStepOperations; | ||
187 | |||
188 | // A pointer to an instance if this structure is passed to the C++ code | ||
189 | // Used to pass basic configuration values to the unmanaged code. | ||
190 | internal ConfigurationParameters[] UnmanagedParams; | ||
191 | |||
192 | // Sometimes you just have to log everything. | ||
193 | public Logging.LogWriter PhysicsLogging; | ||
194 | private bool m_physicsLoggingEnabled; | ||
195 | private string m_physicsLoggingDir; | ||
196 | private string m_physicsLoggingPrefix; | ||
197 | private int m_physicsLoggingFileMinutes; | ||
198 | private bool m_physicsLoggingDoFlush; | ||
199 | private bool m_physicsPhysicalDumpEnabled; | ||
200 | public int PhysicsMetricDumpFrames { get; set; } | ||
201 | // 'true' of the vehicle code is to log lots of details | ||
202 | public bool VehicleLoggingEnabled { get; private set; } | ||
203 | public bool VehiclePhysicalLoggingEnabled { get; private set; } | ||
204 | |||
205 | #region Construction and Initialization | ||
206 | public BSScene(string engineType, string identifier) | ||
207 | { | ||
208 | m_initialized = false; | ||
209 | |||
210 | // The name of the region we're working for is passed to us. Keep for identification. | ||
211 | RegionName = identifier; | ||
212 | |||
213 | // Set identifying variables in the PhysicsScene interface. | ||
214 | EngineType = engineType; | ||
215 | Name = EngineType + "/" + RegionName; | ||
216 | } | ||
217 | |||
218 | // Old version of initialization that assumes legacy sized regions (256x256) | ||
219 | public override void Initialise(IMesher meshmerizer, IConfigSource config) | ||
220 | { | ||
221 | m_log.ErrorFormat("{0} WARNING WARNING WARNING! BulletSim initialized without region extent specification. Terrain will be messed up."); | ||
222 | Vector3 regionExtent = new Vector3( Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); | ||
223 | Initialise(meshmerizer, config, regionExtent); | ||
224 | |||
225 | } | ||
226 | |||
227 | public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent) | ||
228 | { | ||
229 | mesher = meshmerizer; | ||
230 | _taintOperations = new List<TaintCallbackEntry>(); | ||
231 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
232 | _postStepOperations = new List<TaintCallbackEntry>(); | ||
233 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | ||
234 | Shapes = new BSShapeCollection(this); | ||
235 | |||
236 | m_simulatedTime = 0f; | ||
237 | LastTimeStep = 0.1f; | ||
238 | |||
239 | // Allocate pinned memory to pass parameters. | ||
240 | UnmanagedParams = new ConfigurationParameters[1]; | ||
241 | |||
242 | // Set default values for physics parameters plus any overrides from the ini file | ||
243 | GetInitialParameterValues(config); | ||
244 | |||
245 | // Force some parameters to values depending on other configurations | ||
246 | // Only use heightmap terrain implementation if terrain larger than legacy size | ||
247 | if ((uint)regionExtent.X > Constants.RegionSize || (uint)regionExtent.Y > Constants.RegionSize) | ||
248 | { | ||
249 | m_log.WarnFormat("{0} Forcing terrain implementation to heightmap for large region", LogHeader); | ||
250 | BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; | ||
251 | } | ||
252 | |||
253 | // Get the connection to the physics engine (could be native or one of many DLLs) | ||
254 | PE = SelectUnderlyingBulletEngine(BulletEngineName); | ||
255 | |||
256 | // Enable very detailed logging. | ||
257 | // By creating an empty logger when not logging, the log message invocation code | ||
258 | // can be left in and every call doesn't have to check for null. | ||
259 | if (m_physicsLoggingEnabled) | ||
260 | { | ||
261 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush); | ||
262 | PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages. | ||
263 | } | ||
264 | else | ||
265 | { | ||
266 | PhysicsLogging = new Logging.LogWriter(); | ||
267 | } | ||
268 | |||
269 | // Allocate memory for returning of the updates and collisions from the physics engine | ||
270 | m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; | ||
271 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; | ||
272 | |||
273 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | ||
274 | // a child in a mega-region. | ||
275 | // Bullet actually doesn't care about the extents of the simulated | ||
276 | // area. It tracks active objects no matter where they are. | ||
277 | Vector3 worldExtent = regionExtent; | ||
278 | |||
279 | World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray); | ||
280 | |||
281 | Constraints = new BSConstraintCollection(World); | ||
282 | |||
283 | TerrainManager = new BSTerrainManager(this, worldExtent); | ||
284 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | ||
285 | |||
286 | // Put some informational messages into the log file. | ||
287 | m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | ||
288 | |||
289 | InTaintTime = false; | ||
290 | m_initialized = true; | ||
291 | |||
292 | // If the physics engine runs on its own thread, start same. | ||
293 | if (BSParam.UseSeparatePhysicsThread) | ||
294 | { | ||
295 | // The physics simulation should happen independently of the heartbeat loop | ||
296 | m_physicsThread | ||
297 | = WorkManager.StartThread( | ||
298 | BulletSPluginPhysicsThread, | ||
299 | string.Format("{0} ({1})", BulletEngineName, RegionName), | ||
300 | ThreadPriority.Normal, | ||
301 | true, | ||
302 | true); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | // All default parameter values are set here. There should be no values set in the | ||
307 | // variable definitions. | ||
308 | private void GetInitialParameterValues(IConfigSource config) | ||
309 | { | ||
310 | ConfigurationParameters parms = new ConfigurationParameters(); | ||
311 | UnmanagedParams[0] = parms; | ||
312 | |||
313 | BSParam.SetParameterDefaultValues(this); | ||
314 | |||
315 | if (config != null) | ||
316 | { | ||
317 | // If there are specifications in the ini file, use those values | ||
318 | IConfig pConfig = config.Configs["BulletSim"]; | ||
319 | if (pConfig != null) | ||
320 | { | ||
321 | BSParam.SetParameterConfigurationValues(this, pConfig); | ||
322 | |||
323 | // There are two Bullet implementations to choose from | ||
324 | BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged"); | ||
325 | |||
326 | // Very detailed logging for physics debugging | ||
327 | // TODO: the boolean values can be moved to the normal parameter processing. | ||
328 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | ||
329 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | ||
330 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | ||
331 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | ||
332 | m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); | ||
333 | m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false); | ||
334 | // Very detailed logging for vehicle debugging | ||
335 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | ||
336 | VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); | ||
337 | |||
338 | // Do any replacements in the parameters | ||
339 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | ||
340 | } | ||
341 | else | ||
342 | { | ||
343 | // Nothing in the configuration INI file so assume unmanaged and other defaults. | ||
344 | BulletEngineName = "BulletUnmanaged"; | ||
345 | m_physicsLoggingEnabled = false; | ||
346 | VehicleLoggingEnabled = false; | ||
347 | } | ||
348 | |||
349 | // The material characteristics. | ||
350 | BSMaterials.InitializeFromDefaults(Params); | ||
351 | if (pConfig != null) | ||
352 | { | ||
353 | // Let the user add new and interesting material property values. | ||
354 | BSMaterials.InitializefromParameters(pConfig); | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | |||
359 | // A helper function that handles a true/false parameter and returns the proper float number encoding | ||
360 | float ParamBoolean(IConfig config, string parmName, float deflt) | ||
361 | { | ||
362 | float ret = deflt; | ||
363 | if (config.Contains(parmName)) | ||
364 | { | ||
365 | ret = ConfigurationParameters.numericFalse; | ||
366 | if (config.GetBoolean(parmName, false)) | ||
367 | { | ||
368 | ret = ConfigurationParameters.numericTrue; | ||
369 | } | ||
370 | } | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | // Select the connection to the actual Bullet implementation. | ||
375 | // The main engine selection is the engineName up to the first hypen. | ||
376 | // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name | ||
377 | // is passed to the engine to do its special selection, etc. | ||
378 | private BSAPITemplate SelectUnderlyingBulletEngine(string engineName) | ||
379 | { | ||
380 | // For the moment, do a simple switch statement. | ||
381 | // Someday do fancyness with looking up the interfaces in the assembly. | ||
382 | BSAPITemplate ret = null; | ||
383 | |||
384 | string selectionName = engineName.ToLower(); | ||
385 | int hyphenIndex = engineName.IndexOf("-"); | ||
386 | if (hyphenIndex > 0) | ||
387 | selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1); | ||
388 | |||
389 | switch (selectionName) | ||
390 | { | ||
391 | case "bullet": | ||
392 | case "bulletunmanaged": | ||
393 | ret = new BSAPIUnman(engineName, this); | ||
394 | break; | ||
395 | case "bulletxna": | ||
396 | ret = new BSAPIXNA(engineName, this); | ||
397 | // Disable some features that are not implemented in BulletXNA | ||
398 | m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader); | ||
399 | m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader); | ||
400 | BSParam.ShouldUseBulletHACD = false; | ||
401 | m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader); | ||
402 | BSParam.ShouldUseSingleConvexHullForPrims = false; | ||
403 | m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader); | ||
404 | BSParam.ShouldUseGImpactShapeForPrims = false; | ||
405 | m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader); | ||
406 | BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; | ||
407 | break; | ||
408 | } | ||
409 | |||
410 | if (ret == null) | ||
411 | { | ||
412 | m_log.ErrorFormat("{0} COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader); | ||
413 | } | ||
414 | else | ||
415 | { | ||
416 | m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); | ||
417 | } | ||
418 | |||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | public override void Dispose() | ||
423 | { | ||
424 | // m_log.DebugFormat("{0}: Dispose()", LogHeader); | ||
425 | |||
426 | // make sure no stepping happens while we're deleting stuff | ||
427 | m_initialized = false; | ||
428 | |||
429 | lock (PhysObjects) | ||
430 | { | ||
431 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | ||
432 | { | ||
433 | kvp.Value.Destroy(); | ||
434 | } | ||
435 | PhysObjects.Clear(); | ||
436 | } | ||
437 | |||
438 | // Now that the prims are all cleaned up, there should be no constraints left | ||
439 | if (Constraints != null) | ||
440 | { | ||
441 | Constraints.Dispose(); | ||
442 | Constraints = null; | ||
443 | } | ||
444 | |||
445 | if (Shapes != null) | ||
446 | { | ||
447 | Shapes.Dispose(); | ||
448 | Shapes = null; | ||
449 | } | ||
450 | |||
451 | if (TerrainManager != null) | ||
452 | { | ||
453 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
454 | TerrainManager.Dispose(); | ||
455 | TerrainManager = null; | ||
456 | } | ||
457 | |||
458 | // Anything left in the unmanaged code should be cleaned out | ||
459 | PE.Shutdown(World); | ||
460 | |||
461 | // Not logging any more | ||
462 | PhysicsLogging.Close(); | ||
463 | } | ||
464 | #endregion // Construction and Initialization | ||
465 | |||
466 | #region Prim and Avatar addition and removal | ||
467 | |||
468 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) | ||
469 | { | ||
470 | m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); | ||
471 | return null; | ||
472 | } | ||
473 | |||
474 | public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) | ||
475 | { | ||
476 | // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); | ||
477 | |||
478 | if (!m_initialized) return null; | ||
479 | |||
480 | BSCharacter actor = new BSCharacter(localID, avName, this, position, velocity, size, isFlying); | ||
481 | lock (PhysObjects) | ||
482 | PhysObjects.Add(localID, actor); | ||
483 | |||
484 | // TODO: Remove kludge someday. | ||
485 | // We must generate a collision for avatars whether they collide or not. | ||
486 | // This is required by OpenSim to update avatar animations, etc. | ||
487 | lock (AvatarsInSceneLock) | ||
488 | AvatarsInScene.Add(actor); | ||
489 | |||
490 | return actor; | ||
491 | } | ||
492 | |||
493 | public override void RemoveAvatar(PhysicsActor actor) | ||
494 | { | ||
495 | // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); | ||
496 | |||
497 | if (!m_initialized) return; | ||
498 | |||
499 | BSCharacter bsactor = actor as BSCharacter; | ||
500 | if (bsactor != null) | ||
501 | { | ||
502 | try | ||
503 | { | ||
504 | lock (PhysObjects) | ||
505 | PhysObjects.Remove(bsactor.LocalID); | ||
506 | // Remove kludge someday | ||
507 | lock (AvatarsInSceneLock) | ||
508 | AvatarsInScene.Remove(bsactor); | ||
509 | } | ||
510 | catch (Exception e) | ||
511 | { | ||
512 | m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); | ||
513 | } | ||
514 | bsactor.Destroy(); | ||
515 | // bsactor.dispose(); | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}", | ||
520 | LogHeader, actor.LocalID, actor.GetType().Name); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | public override void RemovePrim(PhysicsActor prim) | ||
525 | { | ||
526 | if (!m_initialized) return; | ||
527 | |||
528 | BSPhysObject bsprim = prim as BSPhysObject; | ||
529 | if (bsprim != null) | ||
530 | { | ||
531 | DetailLog("{0},RemovePrim,call", bsprim.LocalID); | ||
532 | // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); | ||
533 | try | ||
534 | { | ||
535 | lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID); | ||
536 | } | ||
537 | catch (Exception e) | ||
538 | { | ||
539 | m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); | ||
540 | } | ||
541 | bsprim.Destroy(); | ||
542 | // bsprim.dispose(); | ||
543 | } | ||
544 | else | ||
545 | { | ||
546 | m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader); | ||
547 | } | ||
548 | } | ||
549 | |||
550 | public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | ||
551 | Vector3 size, Quaternion rotation, bool isPhysical, uint localID) | ||
552 | { | ||
553 | // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); | ||
554 | |||
555 | if (!m_initialized) return null; | ||
556 | |||
557 | // DetailLog("{0},BSScene.AddPrimShape,call", localID); | ||
558 | |||
559 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); | ||
560 | lock (PhysObjects) PhysObjects.Add(localID, prim); | ||
561 | return prim; | ||
562 | } | ||
563 | |||
564 | // This is a call from the simulator saying that some physical property has been updated. | ||
565 | // The BulletSim driver senses the changing of relevant properties so this taint | ||
566 | // information call is not needed. | ||
567 | public override void AddPhysicsActorTaint(PhysicsActor prim) { } | ||
568 | |||
569 | #endregion // Prim and Avatar addition and removal | ||
570 | |||
571 | #region Simulation | ||
572 | |||
573 | // Call from the simulator to send physics information to the simulator objects. | ||
574 | // This pushes all the collision and property update events into the objects in | ||
575 | // the simulator and, since it is on the heartbeat thread, there is an implicit | ||
576 | // locking of those data structures from other heartbeat events. | ||
577 | // If the physics engine is running on a separate thread, the update information | ||
578 | // will be in the ObjectsWithCollions and ObjectsWithUpdates structures. | ||
579 | public override float Simulate(float timeStep) | ||
580 | { | ||
581 | if (!BSParam.UseSeparatePhysicsThread) | ||
582 | { | ||
583 | DoPhysicsStep(timeStep); | ||
584 | } | ||
585 | return SendUpdatesToSimulator(timeStep); | ||
586 | } | ||
587 | |||
588 | // Call the physics engine to do one 'timeStep' and collect collisions and updates | ||
589 | // into ObjectsWithCollisions and ObjectsWithUpdates data structures. | ||
590 | private void DoPhysicsStep(float timeStep) | ||
591 | { | ||
592 | // prevent simulation until we've been initialized | ||
593 | if (!m_initialized) return; | ||
594 | |||
595 | LastTimeStep = timeStep; | ||
596 | |||
597 | int updatedEntityCount = 0; | ||
598 | int collidersCount = 0; | ||
599 | |||
600 | int beforeTime = Util.EnvironmentTickCount(); | ||
601 | int simTime = 0; | ||
602 | |||
603 | int numTaints = _taintOperations.Count; | ||
604 | InTaintTime = true; // Only used for debugging so locking is not necessary. | ||
605 | |||
606 | // update the prim states while we know the physics engine is not busy | ||
607 | ProcessTaints(); | ||
608 | |||
609 | // Some of the physical objects requre individual, pre-step calls | ||
610 | // (vehicles and avatar movement, in particular) | ||
611 | TriggerPreStepEvent(timeStep); | ||
612 | |||
613 | // the prestep actions might have added taints | ||
614 | numTaints += _taintOperations.Count; | ||
615 | ProcessTaints(); | ||
616 | |||
617 | InTaintTime = false; // Only used for debugging so locking is not necessary. | ||
618 | |||
619 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | ||
620 | // Only enable this in a limited test world with few objects. | ||
621 | if (m_physicsPhysicalDumpEnabled) | ||
622 | PE.DumpAllInfo(World); | ||
623 | |||
624 | // step the physical world one interval | ||
625 | m_simulationStep++; | ||
626 | int numSubSteps = 0; | ||
627 | try | ||
628 | { | ||
629 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); | ||
630 | |||
631 | } | ||
632 | catch (Exception e) | ||
633 | { | ||
634 | m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", | ||
635 | LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); | ||
636 | DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", | ||
637 | DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); | ||
638 | updatedEntityCount = 0; | ||
639 | collidersCount = 0; | ||
640 | } | ||
641 | |||
642 | // Make the physics engine dump useful statistics periodically | ||
643 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) | ||
644 | PE.DumpPhysicsStatistics(World); | ||
645 | |||
646 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | ||
647 | SimulationNowTime = Util.EnvironmentTickCount(); | ||
648 | |||
649 | // Send collision information to the colliding objects. The objects decide if the collision | ||
650 | // is 'real' (like linksets don't collide with themselves) and the individual objects | ||
651 | // know if the simulator has subscribed to collisions. | ||
652 | lock (CollisionLock) | ||
653 | { | ||
654 | if (collidersCount > 0) | ||
655 | { | ||
656 | lock (PhysObjects) | ||
657 | { | ||
658 | for (int ii = 0; ii < collidersCount; ii++) | ||
659 | { | ||
660 | uint cA = m_collisionArray[ii].aID; | ||
661 | uint cB = m_collisionArray[ii].bID; | ||
662 | Vector3 point = m_collisionArray[ii].point; | ||
663 | Vector3 normal = m_collisionArray[ii].normal; | ||
664 | float penetration = m_collisionArray[ii].penetration; | ||
665 | SendCollision(cA, cB, point, normal, penetration); | ||
666 | SendCollision(cB, cA, point, -normal, penetration); | ||
667 | } | ||
668 | } | ||
669 | } | ||
670 | } | ||
671 | |||
672 | // If any of the objects had updated properties, tell the managed objects about the update | ||
673 | // and remember that there was a change so it will be passed to the simulator. | ||
674 | lock (UpdateLock) | ||
675 | { | ||
676 | if (updatedEntityCount > 0) | ||
677 | { | ||
678 | lock (PhysObjects) | ||
679 | { | ||
680 | for (int ii = 0; ii < updatedEntityCount; ii++) | ||
681 | { | ||
682 | EntityProperties entprop = m_updateArray[ii]; | ||
683 | BSPhysObject pobj; | ||
684 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
685 | { | ||
686 | if (pobj.IsInitialized) | ||
687 | pobj.UpdateProperties(entprop); | ||
688 | } | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | } | ||
693 | |||
694 | // Some actors want to know when the simulation step is complete. | ||
695 | TriggerPostStepEvent(timeStep); | ||
696 | |||
697 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
698 | if (PhysicsLogging.Enabled) | ||
699 | { | ||
700 | DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
701 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
702 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
703 | } | ||
704 | |||
705 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | ||
706 | // Only enable this in a limited test world with few objects. | ||
707 | if (m_physicsPhysicalDumpEnabled) | ||
708 | PE.DumpAllInfo(World); | ||
709 | |||
710 | // The physics engine returns the number of milliseconds it simulated this call. | ||
711 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | ||
712 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). | ||
713 | m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; | ||
714 | } | ||
715 | |||
716 | // Called by a BSPhysObject to note that it has changed properties and this information | ||
717 | // should be passed up to the simulator at the proper time. | ||
718 | // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so | ||
719 | // this is is under UpdateLock. | ||
720 | public void PostUpdate(BSPhysObject updatee) | ||
721 | { | ||
722 | lock (UpdateLock) | ||
723 | { | ||
724 | ObjectsWithUpdates.Add(updatee); | ||
725 | } | ||
726 | } | ||
727 | |||
728 | // The simulator thinks it is physics time so return all the collisions and position | ||
729 | // updates that were collected in actual physics simulation. | ||
730 | private float SendUpdatesToSimulator(float timeStep) | ||
731 | { | ||
732 | if (!m_initialized) return 5.0f; | ||
733 | |||
734 | DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}", | ||
735 | BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime); | ||
736 | // Push the collisions into the simulator. | ||
737 | lock (CollisionLock) | ||
738 | { | ||
739 | if (ObjectsWithCollisions.Count > 0) | ||
740 | { | ||
741 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
742 | if (!bsp.SendCollisions()) | ||
743 | { | ||
744 | // If the object is done colliding, see that it's removed from the colliding list | ||
745 | ObjectsWithNoMoreCollisions.Add(bsp); | ||
746 | } | ||
747 | } | ||
748 | |||
749 | // This is a kludge to get avatar movement updates. | ||
750 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
751 | // The event updates avatar animations and stuff. | ||
752 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
753 | // Note that we get a copy of the list to search because SendCollision() can take a while. | ||
754 | HashSet<BSPhysObject> tempAvatarsInScene; | ||
755 | lock (AvatarsInSceneLock) | ||
756 | { | ||
757 | tempAvatarsInScene = new HashSet<BSPhysObject>(AvatarsInScene); | ||
758 | } | ||
759 | foreach (BSPhysObject actor in tempAvatarsInScene) | ||
760 | { | ||
761 | if (!ObjectsWithCollisions.Contains(actor)) // don't call avatars twice | ||
762 | actor.SendCollisions(); | ||
763 | } | ||
764 | tempAvatarsInScene = null; | ||
765 | |||
766 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
767 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
768 | // This complex collision processing is required to create an empty collision | ||
769 | // event call after all real collisions have happened on an object. This allows | ||
770 | // the simulator to generate the 'collision end' event. | ||
771 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
772 | { | ||
773 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
774 | ObjectsWithCollisions.Remove(po); | ||
775 | ObjectsWithNoMoreCollisions.Clear(); | ||
776 | } | ||
777 | } | ||
778 | |||
779 | // Call the simulator for each object that has physics property updates. | ||
780 | HashSet<BSPhysObject> updatedObjects = null; | ||
781 | lock (UpdateLock) | ||
782 | { | ||
783 | if (ObjectsWithUpdates.Count > 0) | ||
784 | { | ||
785 | updatedObjects = ObjectsWithUpdates; | ||
786 | ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
787 | } | ||
788 | } | ||
789 | if (updatedObjects != null) | ||
790 | { | ||
791 | foreach (BSPhysObject obj in updatedObjects) | ||
792 | { | ||
793 | obj.RequestPhysicsterseUpdate(); | ||
794 | } | ||
795 | updatedObjects.Clear(); | ||
796 | } | ||
797 | |||
798 | // Return the framerate simulated to give the above returned results. | ||
799 | // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). | ||
800 | float simTime = m_simulatedTime; | ||
801 | m_simulatedTime = 0f; | ||
802 | return simTime; | ||
803 | } | ||
804 | |||
805 | // Something has collided | ||
806 | private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) | ||
807 | { | ||
808 | if (localID <= TerrainManager.HighestTerrainID) | ||
809 | { | ||
810 | return; // don't send collisions to the terrain | ||
811 | } | ||
812 | |||
813 | BSPhysObject collider; | ||
814 | // NOTE that PhysObjects was locked before the call to SendCollision(). | ||
815 | if (!PhysObjects.TryGetValue(localID, out collider)) | ||
816 | { | ||
817 | // If the object that is colliding cannot be found, just ignore the collision. | ||
818 | DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith); | ||
819 | return; | ||
820 | } | ||
821 | |||
822 | // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | ||
823 | BSPhysObject collidee = null; | ||
824 | PhysObjects.TryGetValue(collidingWith, out collidee); | ||
825 | |||
826 | // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); | ||
827 | |||
828 | if (collider.IsInitialized) | ||
829 | { | ||
830 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | ||
831 | { | ||
832 | // If a collision was 'good', remember to send it to the simulator | ||
833 | lock (CollisionLock) | ||
834 | { | ||
835 | ObjectsWithCollisions.Add(collider); | ||
836 | } | ||
837 | } | ||
838 | } | ||
839 | |||
840 | return; | ||
841 | } | ||
842 | |||
843 | public void BulletSPluginPhysicsThread() | ||
844 | { | ||
845 | Thread.CurrentThread.Priority = ThreadPriority.Highest; | ||
846 | m_updateWaitEvent = new ManualResetEvent(false); | ||
847 | |||
848 | while (m_initialized) | ||
849 | { | ||
850 | int beginSimulationRealtimeMS = Util.EnvironmentTickCount(); | ||
851 | |||
852 | if (BSParam.Active) | ||
853 | DoPhysicsStep(BSParam.PhysicsTimeStep); | ||
854 | |||
855 | int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS); | ||
856 | int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS; | ||
857 | |||
858 | if (simulationTimeVsRealtimeDifferenceMS > 0) | ||
859 | { | ||
860 | // The simulation of the time interval took less than realtime. | ||
861 | // Do a wait for the rest of realtime. | ||
862 | m_updateWaitEvent.WaitOne(simulationTimeVsRealtimeDifferenceMS); | ||
863 | //Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); | ||
864 | } | ||
865 | else | ||
866 | { | ||
867 | // The simulation took longer than realtime. | ||
868 | // Do some scaling of simulation time. | ||
869 | // TODO. | ||
870 | DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
871 | } | ||
872 | |||
873 | Watchdog.UpdateThread(); | ||
874 | } | ||
875 | |||
876 | Watchdog.RemoveThread(); | ||
877 | } | ||
878 | |||
879 | #endregion // Simulation | ||
880 | |||
881 | public override void GetResults() { } | ||
882 | |||
883 | #region Terrain | ||
884 | |||
885 | public override void SetTerrain(float[] heightMap) { | ||
886 | TerrainManager.SetTerrain(heightMap); | ||
887 | } | ||
888 | |||
889 | public override void SetWaterLevel(float baseheight) | ||
890 | { | ||
891 | SimpleWaterLevel = baseheight; | ||
892 | } | ||
893 | |||
894 | public override void DeleteTerrain() | ||
895 | { | ||
896 | // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); | ||
897 | } | ||
898 | |||
899 | // Although no one seems to check this, I do support combining. | ||
900 | public override bool SupportsCombining() | ||
901 | { | ||
902 | return TerrainManager.SupportsCombining(); | ||
903 | } | ||
904 | // This call says I am a child to region zero in a mega-region. 'pScene' is that | ||
905 | // of region zero, 'offset' is my offset from regions zero's origin, and | ||
906 | // 'extents' is the largest XY that is handled in my region. | ||
907 | public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) | ||
908 | { | ||
909 | TerrainManager.Combine(pScene, offset, extents); | ||
910 | } | ||
911 | |||
912 | // Unhook all the combining that I know about. | ||
913 | public override void UnCombine(PhysicsScene pScene) | ||
914 | { | ||
915 | TerrainManager.UnCombine(pScene); | ||
916 | } | ||
917 | |||
918 | #endregion // Terrain | ||
919 | |||
920 | public override Dictionary<uint, float> GetTopColliders() | ||
921 | { | ||
922 | Dictionary<uint, float> topColliders; | ||
923 | |||
924 | lock (PhysObjects) | ||
925 | { | ||
926 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | ||
927 | { | ||
928 | kvp.Value.ComputeCollisionScore(); | ||
929 | } | ||
930 | |||
931 | List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values); | ||
932 | orderedPrims.OrderByDescending(p => p.CollisionScore); | ||
933 | topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); | ||
934 | } | ||
935 | |||
936 | return topColliders; | ||
937 | } | ||
938 | |||
939 | public override bool IsThreaded { get { return false; } } | ||
940 | |||
941 | #region Extensions | ||
942 | public override object Extension(string pFunct, params object[] pParams) | ||
943 | { | ||
944 | DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct); | ||
945 | return base.Extension(pFunct, pParams); | ||
946 | } | ||
947 | #endregion // Extensions | ||
948 | |||
949 | public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs) | ||
950 | { | ||
951 | float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f; | ||
952 | float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f; | ||
953 | float pathBegin = (float)pbs.PathBegin * 2.0e-5f; | ||
954 | float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f; | ||
955 | float pathScaleX = (float)(200 - pbs.PathScaleX) * 0.01f; | ||
956 | float pathScaleY = (float)(200 - pbs.PathScaleY) * 0.01f; | ||
957 | float pathTaperX = pbs.PathTaperX * 0.01f; | ||
958 | float pathTaperY = pbs.PathTaperY * 0.01f; | ||
959 | |||
960 | float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f; | ||
961 | float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f; | ||
962 | float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f; | ||
963 | if (profileHollow > 0.95f) | ||
964 | profileHollow = 0.95f; | ||
965 | |||
966 | StringBuilder buff = new StringBuilder(); | ||
967 | buff.Append("shape="); | ||
968 | buff.Append(((ProfileShape)pbs.ProfileShape).ToString()); | ||
969 | buff.Append(","); | ||
970 | buff.Append("hollow="); | ||
971 | buff.Append(((HollowShape)pbs.HollowShape).ToString()); | ||
972 | buff.Append(","); | ||
973 | buff.Append("pathCurve="); | ||
974 | buff.Append(((Extrusion)pbs.PathCurve).ToString()); | ||
975 | buff.Append(","); | ||
976 | buff.Append("profCurve="); | ||
977 | buff.Append(((Extrusion)pbs.ProfileCurve).ToString()); | ||
978 | buff.Append(","); | ||
979 | buff.Append("profHollow="); | ||
980 | buff.Append(profileHollow.ToString()); | ||
981 | buff.Append(","); | ||
982 | buff.Append("pathBegEnd="); | ||
983 | buff.Append(pathBegin.ToString()); | ||
984 | buff.Append("/"); | ||
985 | buff.Append(pathEnd.ToString()); | ||
986 | buff.Append(","); | ||
987 | buff.Append("profileBegEnd="); | ||
988 | buff.Append(profileBegin.ToString()); | ||
989 | buff.Append("/"); | ||
990 | buff.Append(profileEnd.ToString()); | ||
991 | buff.Append(","); | ||
992 | buff.Append("scaleXY="); | ||
993 | buff.Append(pathScaleX.ToString()); | ||
994 | buff.Append("/"); | ||
995 | buff.Append(pathScaleY.ToString()); | ||
996 | buff.Append(","); | ||
997 | buff.Append("shearXY="); | ||
998 | buff.Append(pathShearX.ToString()); | ||
999 | buff.Append("/"); | ||
1000 | buff.Append(pathShearY.ToString()); | ||
1001 | buff.Append(","); | ||
1002 | buff.Append("taperXY="); | ||
1003 | buff.Append(pbs.PathTaperX.ToString()); | ||
1004 | buff.Append("/"); | ||
1005 | buff.Append(pbs.PathTaperY.ToString()); | ||
1006 | buff.Append(","); | ||
1007 | buff.Append("skew="); | ||
1008 | buff.Append(pbs.PathSkew.ToString()); | ||
1009 | buff.Append(","); | ||
1010 | buff.Append("twist/Beg="); | ||
1011 | buff.Append(pbs.PathTwist.ToString()); | ||
1012 | buff.Append("/"); | ||
1013 | buff.Append(pbs.PathTwistBegin.ToString()); | ||
1014 | |||
1015 | return buff.ToString(); | ||
1016 | } | ||
1017 | |||
1018 | #region Taints | ||
1019 | // The simulation execution order is: | ||
1020 | // Simulate() | ||
1021 | // DoOneTimeTaints | ||
1022 | // TriggerPreStepEvent | ||
1023 | // DoOneTimeTaints | ||
1024 | // Step() | ||
1025 | // ProcessAndSendToSimulatorCollisions | ||
1026 | // ProcessAndSendToSimulatorPropertyUpdates | ||
1027 | // TriggerPostStepEvent | ||
1028 | |||
1029 | // Calls to the PhysicsActors can't directly call into the physics engine | ||
1030 | // because it might be busy. We delay changes to a known time. | ||
1031 | // We rely on C#'s closure to save and restore the context for the delegate. | ||
1032 | public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback) | ||
1033 | { | ||
1034 | TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback); | ||
1035 | } | ||
1036 | public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback) | ||
1037 | { | ||
1038 | TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); | ||
1039 | } | ||
1040 | public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback) | ||
1041 | { | ||
1042 | TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback); | ||
1043 | } | ||
1044 | public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback) | ||
1045 | { | ||
1046 | TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); | ||
1047 | } | ||
1048 | // Sometimes a potentially tainted operation can be used in and out of taint time. | ||
1049 | // This routine executes the command immediately if in taint-time otherwise it is queued. | ||
1050 | public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback) | ||
1051 | { | ||
1052 | if (!m_initialized) return; | ||
1053 | |||
1054 | if (inTaintTime) | ||
1055 | pCallback(); | ||
1056 | else | ||
1057 | { | ||
1058 | lock (_taintLock) | ||
1059 | { | ||
1060 | _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback)); | ||
1061 | } | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1065 | private void TriggerPreStepEvent(float timeStep) | ||
1066 | { | ||
1067 | PreStepAction actions = BeforeStep; | ||
1068 | if (actions != null) | ||
1069 | actions(timeStep); | ||
1070 | |||
1071 | } | ||
1072 | |||
1073 | private void TriggerPostStepEvent(float timeStep) | ||
1074 | { | ||
1075 | PostStepAction actions = AfterStep; | ||
1076 | if (actions != null) | ||
1077 | actions(timeStep); | ||
1078 | |||
1079 | } | ||
1080 | |||
1081 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | ||
1082 | // a callback into itself to do the actual property change. That callback is called | ||
1083 | // here just before the physics engine is called to step the simulation. | ||
1084 | public void ProcessTaints() | ||
1085 | { | ||
1086 | ProcessRegularTaints(); | ||
1087 | ProcessPostTaintTaints(); | ||
1088 | } | ||
1089 | |||
1090 | private void ProcessRegularTaints() | ||
1091 | { | ||
1092 | if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process | ||
1093 | { | ||
1094 | // swizzle a new list into the list location so we can process what's there | ||
1095 | List<TaintCallbackEntry> oldList; | ||
1096 | lock (_taintLock) | ||
1097 | { | ||
1098 | oldList = _taintOperations; | ||
1099 | _taintOperations = new List<TaintCallbackEntry>(); | ||
1100 | } | ||
1101 | |||
1102 | foreach (TaintCallbackEntry tcbe in oldList) | ||
1103 | { | ||
1104 | try | ||
1105 | { | ||
1106 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG | ||
1107 | tcbe.callback(); | ||
1108 | } | ||
1109 | catch (Exception e) | ||
1110 | { | ||
1111 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | ||
1112 | } | ||
1113 | } | ||
1114 | oldList.Clear(); | ||
1115 | } | ||
1116 | } | ||
1117 | |||
1118 | // Schedule an update to happen after all the regular taints are processed. | ||
1119 | // Note that new requests for the same operation ("ident") for the same object ("ID") | ||
1120 | // will replace any previous operation by the same object. | ||
1121 | public void PostTaintObject(String ident, uint ID, TaintCallback callback) | ||
1122 | { | ||
1123 | string IDAsString = ID.ToString(); | ||
1124 | string uniqueIdent = ident + "-" + IDAsString; | ||
1125 | lock (_taintLock) | ||
1126 | { | ||
1127 | _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback); | ||
1128 | } | ||
1129 | |||
1130 | return; | ||
1131 | } | ||
1132 | |||
1133 | // Taints that happen after the normal taint processing but before the simulation step. | ||
1134 | private void ProcessPostTaintTaints() | ||
1135 | { | ||
1136 | if (m_initialized && _postTaintOperations.Count > 0) | ||
1137 | { | ||
1138 | Dictionary<string, TaintCallbackEntry> oldList; | ||
1139 | lock (_taintLock) | ||
1140 | { | ||
1141 | oldList = _postTaintOperations; | ||
1142 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
1143 | } | ||
1144 | |||
1145 | foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList) | ||
1146 | { | ||
1147 | try | ||
1148 | { | ||
1149 | DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG | ||
1150 | kvp.Value.callback(); | ||
1151 | } | ||
1152 | catch (Exception e) | ||
1153 | { | ||
1154 | m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e); | ||
1155 | } | ||
1156 | } | ||
1157 | oldList.Clear(); | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | // Only used for debugging. Does not change state of anything so locking is not necessary. | ||
1162 | public bool AssertInTaintTime(string whereFrom) | ||
1163 | { | ||
1164 | if (!InTaintTime) | ||
1165 | { | ||
1166 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | ||
1167 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | ||
1168 | // Util.PrintCallStack(DetailLog); | ||
1169 | } | ||
1170 | return InTaintTime; | ||
1171 | } | ||
1172 | |||
1173 | #endregion // Taints | ||
1174 | |||
1175 | #region IPhysicsParameters | ||
1176 | // Get the list of parameters this physics engine supports | ||
1177 | public PhysParameterEntry[] GetParameterList() | ||
1178 | { | ||
1179 | BSParam.BuildParameterTable(); | ||
1180 | return BSParam.SettableParameters; | ||
1181 | } | ||
1182 | |||
1183 | // Set parameter on a specific or all instances. | ||
1184 | // Return 'false' if not able to set the parameter. | ||
1185 | // Setting the value in the m_params block will change the value the physics engine | ||
1186 | // will use the next time since it's pinned and shared memory. | ||
1187 | // Some of the values require calling into the physics engine to get the new | ||
1188 | // value activated ('terrainFriction' for instance). | ||
1189 | public bool SetPhysicsParameter(string parm, string val, uint localID) | ||
1190 | { | ||
1191 | bool ret = false; | ||
1192 | |||
1193 | BSParam.ParameterDefnBase theParam; | ||
1194 | if (BSParam.TryGetParameter(parm, out theParam)) | ||
1195 | { | ||
1196 | // Set the value in the C# code | ||
1197 | theParam.SetValue(this, val); | ||
1198 | |||
1199 | // Optionally set the parameter in the unmanaged code | ||
1200 | if (theParam.HasSetOnObject) | ||
1201 | { | ||
1202 | // update all the localIDs specified | ||
1203 | // If the local ID is APPLY_TO_NONE, just change the default value | ||
1204 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | ||
1205 | // If the localID is a specific object, apply the parameter change to only that object | ||
1206 | List<uint> objectIDs = new List<uint>(); | ||
1207 | switch (localID) | ||
1208 | { | ||
1209 | case PhysParameterEntry.APPLY_TO_NONE: | ||
1210 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
1211 | objectIDs.Add(TERRAIN_ID); | ||
1212 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1213 | break; | ||
1214 | case PhysParameterEntry.APPLY_TO_ALL: | ||
1215 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | ||
1216 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1217 | break; | ||
1218 | default: | ||
1219 | // setting only one localID | ||
1220 | objectIDs.Add(localID); | ||
1221 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1222 | break; | ||
1223 | } | ||
1224 | } | ||
1225 | |||
1226 | ret = true; | ||
1227 | } | ||
1228 | return ret; | ||
1229 | } | ||
1230 | |||
1231 | // schedule the actual updating of the paramter to when the phys engine is not busy | ||
1232 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val) | ||
1233 | { | ||
1234 | string xval = val; | ||
1235 | List<uint> xlIDs = lIDs; | ||
1236 | string xparm = parm; | ||
1237 | TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() { | ||
1238 | BSParam.ParameterDefnBase thisParam; | ||
1239 | if (BSParam.TryGetParameter(xparm, out thisParam)) | ||
1240 | { | ||
1241 | if (thisParam.HasSetOnObject) | ||
1242 | { | ||
1243 | foreach (uint lID in xlIDs) | ||
1244 | { | ||
1245 | BSPhysObject theObject = null; | ||
1246 | if (PhysObjects.TryGetValue(lID, out theObject)) | ||
1247 | thisParam.SetOnObject(this, theObject); | ||
1248 | } | ||
1249 | } | ||
1250 | } | ||
1251 | }); | ||
1252 | } | ||
1253 | |||
1254 | // Get parameter. | ||
1255 | // Return 'false' if not able to get the parameter. | ||
1256 | public bool GetPhysicsParameter(string parm, out string value) | ||
1257 | { | ||
1258 | string val = String.Empty; | ||
1259 | bool ret = false; | ||
1260 | BSParam.ParameterDefnBase theParam; | ||
1261 | if (BSParam.TryGetParameter(parm, out theParam)) | ||
1262 | { | ||
1263 | val = theParam.GetValue(this); | ||
1264 | ret = true; | ||
1265 | } | ||
1266 | value = val; | ||
1267 | return ret; | ||
1268 | } | ||
1269 | |||
1270 | #endregion IPhysicsParameters | ||
1271 | |||
1272 | // Invoke the detailed logger and output something if it's enabled. | ||
1273 | public void DetailLog(string msg, params Object[] args) | ||
1274 | { | ||
1275 | PhysicsLogging.Write(msg, args); | ||
1276 | } | ||
1277 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | ||
1278 | public const string DetailLogZero = "0000000000"; | ||
1279 | |||
1280 | } | ||
1281 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs new file mode 100755 index 0000000..d1de844 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs | |||
@@ -0,0 +1,425 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OMV = OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Physics.Manager; | ||
33 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public sealed class BSShapeCollection : IDisposable | ||
38 | { | ||
39 | #pragma warning disable 414 | ||
40 | private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; | ||
41 | #pragma warning restore 414 | ||
42 | |||
43 | private BSScene m_physicsScene { get; set; } | ||
44 | |||
45 | private Object m_collectionActivityLock = new Object(); | ||
46 | |||
47 | private bool DDetail = false; | ||
48 | |||
49 | public BSShapeCollection(BSScene physScene) | ||
50 | { | ||
51 | m_physicsScene = physScene; | ||
52 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) | ||
53 | // While detailed debugging is still active, this is better than commenting out all the | ||
54 | // DetailLog statements. When debugging slows down, this and the protected logging | ||
55 | // statements can be commented/removed. | ||
56 | DDetail = true; | ||
57 | } | ||
58 | |||
59 | public void Dispose() | ||
60 | { | ||
61 | // TODO!!!!!!!!! | ||
62 | } | ||
63 | |||
64 | // Callbacks called just before either the body or shape is destroyed. | ||
65 | // Mostly used for changing bodies out from under Linksets. | ||
66 | // Useful for other cases where parameters need saving. | ||
67 | // Passing 'null' says no callback. | ||
68 | public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape); | ||
69 | |||
70 | // Called to update/change the body and shape for an object. | ||
71 | // The object has some shape and body on it. Here we decide if that is the correct shape | ||
72 | // for the current state of the object (static/dynamic/...). | ||
73 | // If bodyCallback is not null, it is called if either the body or the shape are changed | ||
74 | // so dependencies (like constraints) can be removed before the physical object is dereferenced. | ||
75 | // Return 'true' if either the body or the shape changed. | ||
76 | // Called at taint-time. | ||
77 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback) | ||
78 | { | ||
79 | m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); | ||
80 | |||
81 | bool ret = false; | ||
82 | |||
83 | // This lock could probably be pushed down lower but building shouldn't take long | ||
84 | lock (m_collectionActivityLock) | ||
85 | { | ||
86 | // Do we have the correct geometry for this type of object? | ||
87 | // Updates prim.BSShape with information/pointers to shape. | ||
88 | // Returns 'true' of BSShape is changed to a new shape. | ||
89 | bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback); | ||
90 | // If we had to select a new shape geometry for the object, | ||
91 | // rebuild the body around it. | ||
92 | // Updates prim.BSBody with information/pointers to requested body | ||
93 | // Returns 'true' if BSBody was changed. | ||
94 | bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback); | ||
95 | ret = newGeom || newBody; | ||
96 | } | ||
97 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", | ||
98 | prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); | ||
99 | |||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) | ||
104 | { | ||
105 | return GetBodyAndShape(forceRebuild, sim, prim, null); | ||
106 | } | ||
107 | |||
108 | // If the existing prim's shape is to be replaced, remove the tie to the existing shape | ||
109 | // before replacing it. | ||
110 | private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) | ||
111 | { | ||
112 | if (prim.PhysShape.HasPhysicalShape) | ||
113 | { | ||
114 | if (shapeCallback != null) | ||
115 | shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo); | ||
116 | prim.PhysShape.Dereference(m_physicsScene); | ||
117 | } | ||
118 | prim.PhysShape = new BSShapeNull(); | ||
119 | } | ||
120 | |||
121 | // Create the geometry information in Bullet for later use. | ||
122 | // The objects needs a hull if it's physical otherwise a mesh is enough. | ||
123 | // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, | ||
124 | // shared geometries will be used. If the parameters of the existing shape are the same | ||
125 | // as this request, the shape is not rebuilt. | ||
126 | // Info in prim.BSShape is updated to the new shape. | ||
127 | // Returns 'true' if the geometry was rebuilt. | ||
128 | // Called at taint-time! | ||
129 | public const int AvatarShapeCapsule = 0; | ||
130 | public const int AvatarShapeCube = 1; | ||
131 | public const int AvatarShapeOvoid = 2; | ||
132 | public const int AvatarShapeMesh = 3; | ||
133 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) | ||
134 | { | ||
135 | bool ret = false; | ||
136 | bool haveShape = false; | ||
137 | bool nativeShapePossible = true; | ||
138 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
139 | |||
140 | // Kludge to create the capsule for the avatar. | ||
141 | // TDOD: Remove/redo this when BSShapeAvatar is working!! | ||
142 | BSCharacter theChar = prim as BSCharacter; | ||
143 | if (theChar != null) | ||
144 | { | ||
145 | DereferenceExistingShape(prim, shapeCallback); | ||
146 | switch (BSParam.AvatarShape) | ||
147 | { | ||
148 | case AvatarShapeCapsule: | ||
149 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, | ||
150 | BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); | ||
151 | ret = true; | ||
152 | haveShape = true; | ||
153 | break; | ||
154 | case AvatarShapeCube: | ||
155 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, | ||
156 | BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE); | ||
157 | ret = true; | ||
158 | haveShape = true; | ||
159 | break; | ||
160 | case AvatarShapeOvoid: | ||
161 | // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape | ||
162 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, | ||
163 | BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE); | ||
164 | ret = true; | ||
165 | haveShape = true; | ||
166 | break; | ||
167 | case AvatarShapeMesh: | ||
168 | break; | ||
169 | default: | ||
170 | break; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | // If the prim attributes are simple, this could be a simple Bullet native shape | ||
175 | // Native shapes work whether to object is static or physical. | ||
176 | if (!haveShape | ||
177 | && nativeShapePossible | ||
178 | && pbs != null | ||
179 | && PrimHasNoCuts(pbs) | ||
180 | && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ) | ||
181 | ) | ||
182 | { | ||
183 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. | ||
184 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; | ||
185 | if (prim.PhysShape.HasPhysicalShape) | ||
186 | scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); | ||
187 | |||
188 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", | ||
189 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); | ||
190 | |||
191 | // It doesn't look like Bullet scales native spheres so make sure the scales are all equal | ||
192 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | ||
193 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | ||
194 | { | ||
195 | haveShape = true; | ||
196 | if (forceRebuild | ||
197 | || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE | ||
198 | ) | ||
199 | { | ||
200 | DereferenceExistingShape(prim, shapeCallback); | ||
201 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, | ||
202 | BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); | ||
203 | ret = true; | ||
204 | } | ||
205 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", | ||
206 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | ||
207 | } | ||
208 | // If we didn't make a sphere, maybe a box will work. | ||
209 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | ||
210 | { | ||
211 | haveShape = true; | ||
212 | if (forceRebuild | ||
213 | || prim.Scale != scaleOfExistingShape | ||
214 | || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX | ||
215 | ) | ||
216 | { | ||
217 | DereferenceExistingShape(prim, shapeCallback); | ||
218 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, | ||
219 | BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
220 | ret = true; | ||
221 | } | ||
222 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", | ||
223 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | // If a simple shape is not happening, create a mesh and possibly a hull. | ||
228 | if (!haveShape && pbs != null) | ||
229 | { | ||
230 | ret = CreateGeomMeshOrHull(prim, shapeCallback); | ||
231 | } | ||
232 | |||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | // return 'true' if this shape description does not include any cutting or twisting. | ||
237 | public static bool PrimHasNoCuts(PrimitiveBaseShape pbs) | ||
238 | { | ||
239 | return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
240 | && pbs.ProfileHollow == 0 | ||
241 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
242 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
243 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
244 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
245 | && pbs.PathShearX == 0 && pbs.PathShearY == 0; | ||
246 | } | ||
247 | |||
248 | // return 'true' if the prim's shape was changed. | ||
249 | private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) | ||
250 | { | ||
251 | |||
252 | bool ret = false; | ||
253 | // Note that if it's a native shape, the check for physical/non-physical is not | ||
254 | // made. Native shapes work in either case. | ||
255 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) | ||
256 | { | ||
257 | // Use a simple, single mesh convex hull shape if the object is simple enough | ||
258 | BSShape potentialHull = null; | ||
259 | |||
260 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
261 | // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists) | ||
262 | if (BSParam.ShouldUseSingleConvexHullForPrims | ||
263 | && pbs != null | ||
264 | && !pbs.SculptEntry | ||
265 | && PrimHasNoCuts(pbs) | ||
266 | ) | ||
267 | { | ||
268 | potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); | ||
269 | } | ||
270 | // Use the GImpact shape if it is a prim that has some concaveness | ||
271 | if (potentialHull == null | ||
272 | && BSParam.ShouldUseGImpactShapeForPrims | ||
273 | && pbs != null | ||
274 | && !pbs.SculptEntry | ||
275 | ) | ||
276 | { | ||
277 | potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim); | ||
278 | } | ||
279 | // If not any of the simple cases, just make a hull | ||
280 | if (potentialHull == null) | ||
281 | { | ||
282 | potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); | ||
283 | } | ||
284 | |||
285 | // If the current shape is not what is on the prim at the moment, time to change. | ||
286 | if (!prim.PhysShape.HasPhysicalShape | ||
287 | || potentialHull.ShapeType != prim.PhysShape.ShapeType | ||
288 | || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) | ||
289 | { | ||
290 | DereferenceExistingShape(prim, shapeCallback); | ||
291 | prim.PhysShape = potentialHull; | ||
292 | ret = true; | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | // The current shape on the prim is the correct one. We don't need the potential reference. | ||
297 | potentialHull.Dereference(m_physicsScene); | ||
298 | } | ||
299 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); | ||
300 | } | ||
301 | else | ||
302 | { | ||
303 | // Non-physical objects should be just meshes. | ||
304 | BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); | ||
305 | // If the current shape is not what is on the prim at the moment, time to change. | ||
306 | if (!prim.PhysShape.HasPhysicalShape | ||
307 | || potentialMesh.ShapeType != prim.PhysShape.ShapeType | ||
308 | || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) | ||
309 | { | ||
310 | DereferenceExistingShape(prim, shapeCallback); | ||
311 | prim.PhysShape = potentialMesh; | ||
312 | ret = true; | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | // We don't need this reference to the mesh that is already being using. | ||
317 | potentialMesh.Dereference(m_physicsScene); | ||
318 | } | ||
319 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); | ||
320 | } | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | // Track another user of a body. | ||
325 | // We presume the caller has allocated the body. | ||
326 | // Bodies only have one user so the body is just put into the world if not already there. | ||
327 | private void ReferenceBody(BulletBody body) | ||
328 | { | ||
329 | lock (m_collectionActivityLock) | ||
330 | { | ||
331 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | ||
332 | if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body)) | ||
333 | { | ||
334 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body); | ||
335 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
336 | } | ||
337 | } | ||
338 | } | ||
339 | |||
340 | // Release the usage of a body. | ||
341 | // Called when releasing use of a BSBody. BSShape is handled separately. | ||
342 | // Called in taint time. | ||
343 | public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback ) | ||
344 | { | ||
345 | if (!body.HasPhysicalBody) | ||
346 | return; | ||
347 | |||
348 | m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); | ||
349 | |||
350 | lock (m_collectionActivityLock) | ||
351 | { | ||
352 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); | ||
353 | // If the caller needs to know the old body is going away, pass the event up. | ||
354 | if (bodyCallback != null) | ||
355 | bodyCallback(body, null); | ||
356 | |||
357 | // Removing an object not in the world is a NOOP | ||
358 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body); | ||
359 | |||
360 | // Zero any reference to the shape so it is not freed when the body is deleted. | ||
361 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null); | ||
362 | |||
363 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, body); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | // Create a body object in Bullet. | ||
368 | // Updates prim.BSBody with the information about the new body if one is created. | ||
369 | // Returns 'true' if an object was actually created. | ||
370 | // Called at taint-time. | ||
371 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback) | ||
372 | { | ||
373 | bool ret = false; | ||
374 | |||
375 | // the mesh, hull or native shape must have already been created in Bullet | ||
376 | bool mustRebuild = !prim.PhysBody.HasPhysicalBody; | ||
377 | |||
378 | // If there is an existing body, verify it's of an acceptable type. | ||
379 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | ||
380 | if (!mustRebuild) | ||
381 | { | ||
382 | CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody); | ||
383 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | ||
384 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | ||
385 | { | ||
386 | // If the collisionObject is not the correct type for solidness, rebuild what's there | ||
387 | mustRebuild = true; | ||
388 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | if (mustRebuild || forceRebuild) | ||
393 | { | ||
394 | // Free any old body | ||
395 | DereferenceBody(prim.PhysBody, bodyCallback); | ||
396 | |||
397 | BulletBody aBody; | ||
398 | if (prim.IsSolid) | ||
399 | { | ||
400 | aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
401 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody); | ||
402 | } | ||
403 | else | ||
404 | { | ||
405 | aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
406 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); | ||
407 | } | ||
408 | |||
409 | ReferenceBody(aBody); | ||
410 | |||
411 | prim.PhysBody = aBody; | ||
412 | |||
413 | ret = true; | ||
414 | } | ||
415 | |||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | private void DetailLog(string msg, params Object[] args) | ||
420 | { | ||
421 | if (m_physicsScene.PhysicsLogging.Enabled) | ||
422 | m_physicsScene.DetailLog(msg, args); | ||
423 | } | ||
424 | } | ||
425 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs new file mode 100755 index 0000000..86d86cb --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs | |||
@@ -0,0 +1,1463 @@ | |||
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 copyrightD | ||
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.Text; | ||
31 | |||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | using OpenSim.Region.Physics.Meshing; | ||
35 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
36 | |||
37 | using OMV = OpenMetaverse; | ||
38 | |||
39 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
40 | { | ||
41 | // Information class that holds stats for the shape. Which values mean | ||
42 | // something depends on the type of shape. | ||
43 | // This information is used for debugging and stats and is not used | ||
44 | // for operational things. | ||
45 | public class ShapeInfoInfo | ||
46 | { | ||
47 | public int Vertices { get; set; } | ||
48 | private int m_hullCount; | ||
49 | private int[] m_verticesPerHull; | ||
50 | public ShapeInfoInfo() | ||
51 | { | ||
52 | Vertices = 0; | ||
53 | m_hullCount = 0; | ||
54 | m_verticesPerHull = null; | ||
55 | } | ||
56 | public int HullCount | ||
57 | { | ||
58 | set | ||
59 | { | ||
60 | m_hullCount = value; | ||
61 | m_verticesPerHull = new int[m_hullCount]; | ||
62 | Array.Clear(m_verticesPerHull, 0, m_hullCount); | ||
63 | } | ||
64 | get { return m_hullCount; } | ||
65 | } | ||
66 | public void SetVerticesPerHull(int hullNum, int vertices) | ||
67 | { | ||
68 | if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) | ||
69 | { | ||
70 | m_verticesPerHull[hullNum] = vertices; | ||
71 | } | ||
72 | } | ||
73 | public int GetVerticesPerHull(int hullNum) | ||
74 | { | ||
75 | if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) | ||
76 | { | ||
77 | return m_verticesPerHull[hullNum]; | ||
78 | } | ||
79 | return 0; | ||
80 | } | ||
81 | public override string ToString() | ||
82 | { | ||
83 | StringBuilder buff = new StringBuilder(); | ||
84 | // buff.Append("ShapeInfo=<"); | ||
85 | buff.Append("<"); | ||
86 | if (Vertices > 0) | ||
87 | { | ||
88 | buff.Append("verts="); | ||
89 | buff.Append(Vertices.ToString()); | ||
90 | } | ||
91 | |||
92 | if (Vertices > 0 && HullCount > 0) buff.Append(","); | ||
93 | |||
94 | if (HullCount > 0) | ||
95 | { | ||
96 | buff.Append("nHulls="); | ||
97 | buff.Append(HullCount.ToString()); | ||
98 | buff.Append(","); | ||
99 | buff.Append("hullVerts="); | ||
100 | for (int ii = 0; ii < HullCount; ii++) | ||
101 | { | ||
102 | if (ii != 0) buff.Append(","); | ||
103 | buff.Append(GetVerticesPerHull(ii).ToString()); | ||
104 | } | ||
105 | } | ||
106 | buff.Append(">"); | ||
107 | return buff.ToString(); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | public abstract class BSShape | ||
112 | { | ||
113 | private static string LogHeader = "[BULLETSIM SHAPE]"; | ||
114 | |||
115 | public int referenceCount { get; set; } | ||
116 | public DateTime lastReferenced { get; set; } | ||
117 | public BulletShape physShapeInfo { get; set; } | ||
118 | public ShapeInfoInfo shapeInfo { get; private set; } | ||
119 | |||
120 | public BSShape() | ||
121 | { | ||
122 | referenceCount = 1; | ||
123 | lastReferenced = DateTime.Now; | ||
124 | physShapeInfo = new BulletShape(); | ||
125 | shapeInfo = new ShapeInfoInfo(); | ||
126 | } | ||
127 | public BSShape(BulletShape pShape) | ||
128 | { | ||
129 | referenceCount = 1; | ||
130 | lastReferenced = DateTime.Now; | ||
131 | physShapeInfo = pShape; | ||
132 | shapeInfo = new ShapeInfoInfo(); | ||
133 | } | ||
134 | |||
135 | // Get another reference to this shape. | ||
136 | public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim); | ||
137 | |||
138 | // Called when this shape is being used again. | ||
139 | // Used internally. External callers should call instance.GetReference() to properly copy/reference | ||
140 | // the shape. | ||
141 | protected virtual void IncrementReference() | ||
142 | { | ||
143 | referenceCount++; | ||
144 | lastReferenced = DateTime.Now; | ||
145 | } | ||
146 | |||
147 | // Called when this shape is done being used. | ||
148 | protected virtual void DecrementReference() | ||
149 | { | ||
150 | referenceCount--; | ||
151 | lastReferenced = DateTime.Now; | ||
152 | } | ||
153 | |||
154 | // Release the use of a physical shape. | ||
155 | public abstract void Dereference(BSScene physicsScene); | ||
156 | |||
157 | // Return 'true' if there is an allocated physics physical shape under this class instance. | ||
158 | public virtual bool HasPhysicalShape | ||
159 | { | ||
160 | get | ||
161 | { | ||
162 | if (physShapeInfo != null) | ||
163 | return physShapeInfo.HasPhysicalShape; | ||
164 | return false; | ||
165 | } | ||
166 | } | ||
167 | public virtual BSPhysicsShapeType ShapeType | ||
168 | { | ||
169 | get | ||
170 | { | ||
171 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
172 | if (physShapeInfo != null && physShapeInfo.HasPhysicalShape) | ||
173 | ret = physShapeInfo.shapeType; | ||
174 | return ret; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | // Returns a string for debugging that uniquily identifies the memory used by this instance | ||
179 | public virtual string AddrString | ||
180 | { | ||
181 | get | ||
182 | { | ||
183 | if (physShapeInfo != null) | ||
184 | return physShapeInfo.AddrString; | ||
185 | return "unknown"; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | public override string ToString() | ||
190 | { | ||
191 | StringBuilder buff = new StringBuilder(); | ||
192 | if (physShapeInfo == null) | ||
193 | { | ||
194 | buff.Append("<noPhys"); | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | buff.Append("<phy="); | ||
199 | buff.Append(physShapeInfo.ToString()); | ||
200 | } | ||
201 | buff.Append(",c="); | ||
202 | buff.Append(referenceCount.ToString()); | ||
203 | buff.Append(">"); | ||
204 | return buff.ToString(); | ||
205 | } | ||
206 | |||
207 | #region Common shape routines | ||
208 | // Create a hash of all the shape parameters to be used as a key for this particular shape. | ||
209 | public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | ||
210 | { | ||
211 | // level of detail based on size and type of the object | ||
212 | float lod = BSParam.MeshLOD; | ||
213 | if (pbs.SculptEntry) | ||
214 | lod = BSParam.SculptLOD; | ||
215 | |||
216 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
217 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | ||
218 | if (maxAxis > BSParam.MeshMegaPrimThreshold) | ||
219 | lod = BSParam.MeshMegaPrimLOD; | ||
220 | |||
221 | retLod = lod; | ||
222 | return pbs.GetMeshKey(size, lod); | ||
223 | } | ||
224 | |||
225 | // The creation of a mesh or hull can fail if an underlying asset is not available. | ||
226 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; | ||
227 | // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). | ||
228 | // The first case causes the asset to be fetched. The second case requires | ||
229 | // us to not loop forever. | ||
230 | // Called after creating a physical mesh or hull. If the physical shape was created, | ||
231 | // just return. | ||
232 | public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) | ||
233 | { | ||
234 | // If the shape was successfully created, nothing more to do | ||
235 | if (newShape.HasPhysicalShape) | ||
236 | return newShape; | ||
237 | |||
238 | // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been | ||
239 | // fetched but we end up here again, the meshing of the asset must have failed. | ||
240 | // Prevent trying to keep fetching the mesh by declaring failure. | ||
241 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
242 | { | ||
243 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; | ||
244 | physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}", | ||
245 | LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
246 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}", | ||
247 | prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | ||
252 | if (prim.BaseShape.SculptEntry | ||
253 | && !prim.AssetFailed() | ||
254 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting | ||
255 | && prim.BaseShape.SculptTexture != OMV.UUID.Zero | ||
256 | ) | ||
257 | { | ||
258 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}", | ||
259 | prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
260 | // Multiple requestors will know we're waiting for this asset | ||
261 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; | ||
262 | |||
263 | BSPhysObject xprim = prim; | ||
264 | RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; | ||
265 | if (assetProvider != null) | ||
266 | { | ||
267 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
268 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
269 | { | ||
270 | // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); | ||
271 | bool assetFound = false; | ||
272 | string mismatchIDs = String.Empty; // DEBUG DEBUG | ||
273 | if (asset != null && yprim.BaseShape.SculptEntry) | ||
274 | { | ||
275 | if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) | ||
276 | { | ||
277 | yprim.BaseShape.SculptData = asset.Data; | ||
278 | // This will cause the prim to see that the filler shape is not the right | ||
279 | // one and try again to build the object. | ||
280 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
281 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; | ||
282 | yprim.ForceBodyShapeRebuild(false /* inTaintTime */); | ||
283 | assetFound = true; | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; | ||
288 | } | ||
289 | } | ||
290 | if (!assetFound) | ||
291 | { | ||
292 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; | ||
293 | } | ||
294 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", | ||
295 | yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); | ||
296 | }); | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; | ||
301 | physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", | ||
302 | LogHeader, physicsScene.Name); | ||
303 | } | ||
304 | } | ||
305 | else | ||
306 | { | ||
307 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) | ||
308 | { | ||
309 | physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}", | ||
310 | LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
311 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}", | ||
312 | prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
313 | } | ||
314 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) | ||
315 | { | ||
316 | physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}", | ||
317 | LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
318 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}", | ||
319 | prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | |||
324 | // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. | ||
325 | BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
326 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID); | ||
327 | |||
328 | return fillShape.physShapeInfo; | ||
329 | } | ||
330 | |||
331 | public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim) | ||
332 | { | ||
333 | StringBuilder buff = new StringBuilder(prim.PhysObjectName); | ||
334 | buff.Append("/pos="); | ||
335 | buff.Append(prim.RawPosition.ToString()); | ||
336 | if (pScene != null) | ||
337 | { | ||
338 | buff.Append("/rgn="); | ||
339 | buff.Append(pScene.Name); | ||
340 | } | ||
341 | return buff.ToString(); | ||
342 | } | ||
343 | |||
344 | #endregion // Common shape routines | ||
345 | } | ||
346 | |||
347 | // ============================================================================================================ | ||
348 | public class BSShapeNull : BSShape | ||
349 | { | ||
350 | public BSShapeNull() : base() | ||
351 | { | ||
352 | } | ||
353 | public static BSShape GetReference() { return new BSShapeNull(); } | ||
354 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); } | ||
355 | public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } | ||
356 | } | ||
357 | |||
358 | // ============================================================================================================ | ||
359 | // BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere. | ||
360 | // They are odd in that they don't allocate meshes but are computated/procedural. | ||
361 | // This means allocation and freeing is different than meshes. | ||
362 | public class BSShapeNative : BSShape | ||
363 | { | ||
364 | private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; | ||
365 | public BSShapeNative(BulletShape pShape) : base(pShape) | ||
366 | { | ||
367 | } | ||
368 | |||
369 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, | ||
370 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
371 | { | ||
372 | // Native shapes are not shared and are always built anew. | ||
373 | return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); | ||
374 | } | ||
375 | |||
376 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
377 | { | ||
378 | // Native shapes are not shared so we return a new shape. | ||
379 | BSShape ret = null; | ||
380 | lock (physShapeInfo) | ||
381 | { | ||
382 | ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, | ||
383 | physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey)); | ||
384 | } | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | // Make this reference to the physical shape go away since native shapes are not shared. | ||
389 | public override void Dereference(BSScene physicsScene) | ||
390 | { | ||
391 | // Native shapes are not tracked and are released immediately | ||
392 | lock (physShapeInfo) | ||
393 | { | ||
394 | if (physShapeInfo.HasPhysicalShape) | ||
395 | { | ||
396 | physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | ||
397 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | ||
398 | } | ||
399 | physShapeInfo.Clear(); | ||
400 | // Garbage collection will free up this instance. | ||
401 | } | ||
402 | } | ||
403 | |||
404 | private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, | ||
405 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
406 | { | ||
407 | BulletShape newShape; | ||
408 | |||
409 | ShapeData nativeShapeData = new ShapeData(); | ||
410 | nativeShapeData.Type = shapeType; | ||
411 | nativeShapeData.ID = prim.LocalID; | ||
412 | nativeShapeData.Scale = prim.Scale; | ||
413 | nativeShapeData.Size = prim.Scale; | ||
414 | nativeShapeData.MeshKey = (ulong)shapeKey; | ||
415 | nativeShapeData.HullKey = (ulong)shapeKey; | ||
416 | |||
417 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | ||
418 | { | ||
419 | newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); | ||
420 | physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); | ||
421 | } | ||
422 | else | ||
423 | { | ||
424 | newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); | ||
425 | } | ||
426 | if (!newShape.HasPhysicalShape) | ||
427 | { | ||
428 | physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | ||
429 | LogHeader, prim.LocalID, shapeType); | ||
430 | } | ||
431 | newShape.shapeType = shapeType; | ||
432 | newShape.isNativeShape = true; | ||
433 | newShape.shapeKey = (UInt64)shapeKey; | ||
434 | return newShape; | ||
435 | } | ||
436 | |||
437 | } | ||
438 | |||
439 | // ============================================================================================================ | ||
440 | // BSShapeMesh is a simple mesh. | ||
441 | public class BSShapeMesh : BSShape | ||
442 | { | ||
443 | private static string LogHeader = "[BULLETSIM SHAPE MESH]"; | ||
444 | public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); | ||
445 | |||
446 | public BSShapeMesh(BulletShape pShape) : base(pShape) | ||
447 | { | ||
448 | } | ||
449 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
450 | { | ||
451 | float lod; | ||
452 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
453 | |||
454 | BSShapeMesh retMesh = null; | ||
455 | lock (Meshes) | ||
456 | { | ||
457 | if (Meshes.TryGetValue(newMeshKey, out retMesh)) | ||
458 | { | ||
459 | // The mesh has already been created. Return a new reference to same. | ||
460 | retMesh.IncrementReference(); | ||
461 | } | ||
462 | else | ||
463 | { | ||
464 | retMesh = new BSShapeMesh(new BulletShape()); | ||
465 | // An instance of this mesh has not been created. Build and remember same. | ||
466 | BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
467 | |||
468 | // Check to see if mesh was created (might require an asset). | ||
469 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
470 | if (!newShape.isNativeShape || prim.AssetFailed() ) | ||
471 | { | ||
472 | // If a mesh was what was created, remember the built shape for later sharing. | ||
473 | // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. | ||
474 | Meshes.Add(newMeshKey, retMesh); | ||
475 | } | ||
476 | |||
477 | retMesh.physShapeInfo = newShape; | ||
478 | } | ||
479 | } | ||
480 | physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); | ||
481 | return retMesh; | ||
482 | } | ||
483 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
484 | { | ||
485 | BSShape ret = null; | ||
486 | // If the underlying shape is native, the actual shape has not been build (waiting for asset) | ||
487 | // and we must create a copy of the native shape since they are never shared. | ||
488 | if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) | ||
489 | { | ||
490 | // TODO: decide when the native shapes should be freed. Check in Dereference? | ||
491 | ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
492 | } | ||
493 | else | ||
494 | { | ||
495 | // Another reference to this shape is just counted. | ||
496 | IncrementReference(); | ||
497 | ret = this; | ||
498 | } | ||
499 | return ret; | ||
500 | } | ||
501 | public override void Dereference(BSScene physicsScene) | ||
502 | { | ||
503 | lock (Meshes) | ||
504 | { | ||
505 | this.DecrementReference(); | ||
506 | physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
507 | // TODO: schedule aging and destruction of unused meshes. | ||
508 | } | ||
509 | } | ||
510 | // Loop through all the known meshes and return the description based on the physical address. | ||
511 | public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh) | ||
512 | { | ||
513 | bool ret = false; | ||
514 | BSShapeMesh foundDesc = null; | ||
515 | lock (Meshes) | ||
516 | { | ||
517 | foreach (BSShapeMesh sm in Meshes.Values) | ||
518 | { | ||
519 | if (sm.physShapeInfo.ReferenceSame(pShape)) | ||
520 | { | ||
521 | foundDesc = sm; | ||
522 | ret = true; | ||
523 | break; | ||
524 | } | ||
525 | |||
526 | } | ||
527 | } | ||
528 | outMesh = foundDesc; | ||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices ); | ||
533 | private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
534 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
535 | { | ||
536 | return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, | ||
537 | (w, iC, i, vC, v) => | ||
538 | { | ||
539 | shapeInfo.Vertices = vC; | ||
540 | return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v); | ||
541 | }); | ||
542 | } | ||
543 | |||
544 | // Code that uses the mesher to create the index/vertices info for a trimesh shape. | ||
545 | // This is used by the passed 'makeShape' call to create the Bullet mesh shape. | ||
546 | // The actual build call is passed so this logic can be used by several of the shapes that use a | ||
547 | // simple mesh as their base shape. | ||
548 | public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
549 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape) | ||
550 | { | ||
551 | BulletShape newShape = new BulletShape(); | ||
552 | |||
553 | IMesh meshData = null; | ||
554 | lock (physicsScene.mesher) | ||
555 | { | ||
556 | meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, | ||
557 | false, // say it is not physical so a bounding box is not built | ||
558 | false // do not cache the mesh and do not use previously built versions | ||
559 | ); | ||
560 | } | ||
561 | |||
562 | if (meshData != null) | ||
563 | { | ||
564 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
565 | { | ||
566 | // Release the fetched asset data once it has been used. | ||
567 | pbs.SculptData = new byte[0]; | ||
568 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; | ||
569 | } | ||
570 | |||
571 | int[] indices = meshData.getIndexListAsInt(); | ||
572 | int realIndicesIndex = indices.Length; | ||
573 | float[] verticesAsFloats = meshData.getVertexListAsFloat(); | ||
574 | |||
575 | if (BSParam.ShouldRemoveZeroWidthTriangles) | ||
576 | { | ||
577 | // Remove degenerate triangles. These are triangles with two of the vertices | ||
578 | // are the same. This is complicated by the problem that vertices are not | ||
579 | // made unique in sculpties so we have to compare the values in the vertex. | ||
580 | realIndicesIndex = 0; | ||
581 | for (int tri = 0; tri < indices.Length; tri += 3) | ||
582 | { | ||
583 | // Compute displacements into vertex array for each vertex of the triangle | ||
584 | int v1 = indices[tri + 0] * 3; | ||
585 | int v2 = indices[tri + 1] * 3; | ||
586 | int v3 = indices[tri + 2] * 3; | ||
587 | // Check to see if any two of the vertices are the same | ||
588 | if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] | ||
589 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] | ||
590 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) | ||
591 | || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] | ||
592 | && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] | ||
593 | && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) | ||
594 | || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] | ||
595 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] | ||
596 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) | ||
597 | ) | ||
598 | { | ||
599 | // None of the vertices of the triangles are the same. This is a good triangle; | ||
600 | indices[realIndicesIndex + 0] = indices[tri + 0]; | ||
601 | indices[realIndicesIndex + 1] = indices[tri + 1]; | ||
602 | indices[realIndicesIndex + 2] = indices[tri + 2]; | ||
603 | realIndicesIndex += 3; | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", | ||
608 | BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); | ||
609 | |||
610 | if (realIndicesIndex != 0) | ||
611 | { | ||
612 | newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); | ||
613 | } | ||
614 | else | ||
615 | { | ||
616 | // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. | ||
617 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; | ||
618 | physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) ); | ||
619 | physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); | ||
620 | } | ||
621 | } | ||
622 | newShape.shapeKey = newMeshKey; | ||
623 | |||
624 | return newShape; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | // ============================================================================================================ | ||
629 | // BSShapeHull is a physical shape representation htat is made up of many convex hulls. | ||
630 | // The convex hulls are either supplied with the asset or are approximated by one of the | ||
631 | // convex hull creation routines (in OpenSim or in Bullet). | ||
632 | public class BSShapeHull : BSShape | ||
633 | { | ||
634 | #pragma warning disable 414 | ||
635 | private static string LogHeader = "[BULLETSIM SHAPE HULL]"; | ||
636 | #pragma warning restore 414 | ||
637 | |||
638 | public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); | ||
639 | |||
640 | |||
641 | public BSShapeHull(BulletShape pShape) : base(pShape) | ||
642 | { | ||
643 | } | ||
644 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
645 | { | ||
646 | float lod; | ||
647 | System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
648 | |||
649 | BSShapeHull retHull = null; | ||
650 | lock (Hulls) | ||
651 | { | ||
652 | if (Hulls.TryGetValue(newHullKey, out retHull)) | ||
653 | { | ||
654 | // The mesh has already been created. Return a new reference to same. | ||
655 | retHull.IncrementReference(); | ||
656 | } | ||
657 | else | ||
658 | { | ||
659 | retHull = new BSShapeHull(new BulletShape()); | ||
660 | // An instance of this mesh has not been created. Build and remember same. | ||
661 | BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); | ||
662 | |||
663 | // Check to see if hull was created (might require an asset). | ||
664 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
665 | if (!newShape.isNativeShape || prim.AssetFailed()) | ||
666 | { | ||
667 | // If a mesh was what was created, remember the built shape for later sharing. | ||
668 | Hulls.Add(newHullKey, retHull); | ||
669 | } | ||
670 | retHull.physShapeInfo = newShape; | ||
671 | } | ||
672 | } | ||
673 | physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); | ||
674 | return retHull; | ||
675 | } | ||
676 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
677 | { | ||
678 | BSShape ret = null; | ||
679 | // If the underlying shape is native, the actual shape has not been build (waiting for asset) | ||
680 | // and we must create a copy of the native shape since they are never shared. | ||
681 | if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) | ||
682 | { | ||
683 | // TODO: decide when the native shapes should be freed. Check in Dereference? | ||
684 | ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
685 | } | ||
686 | else | ||
687 | { | ||
688 | // Another reference to this shape is just counted. | ||
689 | IncrementReference(); | ||
690 | ret = this; | ||
691 | } | ||
692 | return ret; | ||
693 | } | ||
694 | public override void Dereference(BSScene physicsScene) | ||
695 | { | ||
696 | lock (Hulls) | ||
697 | { | ||
698 | this.DecrementReference(); | ||
699 | physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
700 | // TODO: schedule aging and destruction of unused meshes. | ||
701 | } | ||
702 | } | ||
703 | |||
704 | List<ConvexResult> m_hulls; | ||
705 | private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, | ||
706 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
707 | { | ||
708 | BulletShape newShape = new BulletShape(); | ||
709 | |||
710 | IMesh meshData = null; | ||
711 | List<List<OMV.Vector3>> allHulls = null; | ||
712 | lock (physicsScene.mesher) | ||
713 | { | ||
714 | // Pass true for physicalness as this prevents the creation of bounding box which is not needed | ||
715 | meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); | ||
716 | |||
717 | // If we should use the asset's hull info, fetch it out of the locked mesher | ||
718 | if (meshData != null && BSParam.ShouldUseAssetHulls) | ||
719 | { | ||
720 | Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; | ||
721 | if (realMesher != null) | ||
722 | { | ||
723 | allHulls = realMesher.GetConvexHulls(size); | ||
724 | } | ||
725 | if (allHulls == null) | ||
726 | { | ||
727 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID); | ||
728 | } | ||
729 | } | ||
730 | } | ||
731 | |||
732 | // If there is hull data in the mesh asset, build the hull from that | ||
733 | if (allHulls != null && BSParam.ShouldUseAssetHulls) | ||
734 | { | ||
735 | int hullCount = allHulls.Count; | ||
736 | shapeInfo.HullCount = hullCount; | ||
737 | int totalVertices = 1; // include one for the count of the hulls | ||
738 | // Using the structure described for HACD hulls, create the memory sturcture | ||
739 | // to pass the hull data to the creater. | ||
740 | foreach (List<OMV.Vector3> hullVerts in allHulls) | ||
741 | { | ||
742 | totalVertices += 4; // add four for the vertex count and centroid | ||
743 | totalVertices += hullVerts.Count * 3; // one vertex is three dimensions | ||
744 | } | ||
745 | float[] convHulls = new float[totalVertices]; | ||
746 | |||
747 | convHulls[0] = (float)hullCount; | ||
748 | int jj = 1; | ||
749 | int hullIndex = 0; | ||
750 | foreach (List<OMV.Vector3> hullVerts in allHulls) | ||
751 | { | ||
752 | convHulls[jj + 0] = hullVerts.Count; | ||
753 | convHulls[jj + 1] = 0f; // centroid x,y,z | ||
754 | convHulls[jj + 2] = 0f; | ||
755 | convHulls[jj + 3] = 0f; | ||
756 | jj += 4; | ||
757 | foreach (OMV.Vector3 oneVert in hullVerts) | ||
758 | { | ||
759 | convHulls[jj + 0] = oneVert.X; | ||
760 | convHulls[jj + 1] = oneVert.Y; | ||
761 | convHulls[jj + 2] = oneVert.Z; | ||
762 | jj += 3; | ||
763 | } | ||
764 | shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count); | ||
765 | hullIndex++; | ||
766 | } | ||
767 | |||
768 | // create the hull data structure in Bullet | ||
769 | newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); | ||
770 | |||
771 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", | ||
772 | prim.LocalID, hullCount, totalVertices, newShape); | ||
773 | } | ||
774 | |||
775 | // If no hull specified in the asset and we should use Bullet's HACD approximation... | ||
776 | if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) | ||
777 | { | ||
778 | // Build the hull shape from an existing mesh shape. | ||
779 | // The mesh should have already been created in Bullet. | ||
780 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID); | ||
781 | BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); | ||
782 | |||
783 | if (meshShape.physShapeInfo.HasPhysicalShape) | ||
784 | { | ||
785 | HACDParams parms = new HACDParams(); | ||
786 | parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; | ||
787 | parms.minClusters = BSParam.BHullMinClusters; | ||
788 | parms.compacityWeight = BSParam.BHullCompacityWeight; | ||
789 | parms.volumeWeight = BSParam.BHullVolumeWeight; | ||
790 | parms.concavity = BSParam.BHullConcavity; | ||
791 | parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); | ||
792 | parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); | ||
793 | parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); | ||
794 | parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); | ||
795 | parms.whichHACD = 0; // Use the HACD routine that comes with Bullet | ||
796 | |||
797 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); | ||
798 | newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); | ||
799 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); | ||
800 | |||
801 | // Now done with the mesh shape. | ||
802 | shapeInfo.HullCount = 1; | ||
803 | BSShapeMesh maybeMesh = meshShape as BSShapeMesh; | ||
804 | if (maybeMesh != null) | ||
805 | shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices); | ||
806 | meshShape.Dereference(physicsScene); | ||
807 | } | ||
808 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | ||
809 | } | ||
810 | |||
811 | // If no other hull specifications, use our HACD hull approximation. | ||
812 | if (!newShape.HasPhysicalShape && meshData != null) | ||
813 | { | ||
814 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
815 | { | ||
816 | // Release the fetched asset data once it has been used. | ||
817 | pbs.SculptData = new byte[0]; | ||
818 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; | ||
819 | } | ||
820 | |||
821 | int[] indices = meshData.getIndexListAsInt(); | ||
822 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
823 | |||
824 | //format conversion from IMesh format to DecompDesc format | ||
825 | List<int> convIndices = new List<int>(); | ||
826 | List<float3> convVertices = new List<float3>(); | ||
827 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
828 | { | ||
829 | convIndices.Add(indices[ii]); | ||
830 | } | ||
831 | foreach (OMV.Vector3 vv in vertices) | ||
832 | { | ||
833 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
834 | } | ||
835 | |||
836 | uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; | ||
837 | if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) | ||
838 | { | ||
839 | // Simple primitive shapes we know are convex so they are better implemented with | ||
840 | // fewer hulls. | ||
841 | // Check for simple shape (prim without cuts) and reduce split parameter if so. | ||
842 | if (BSShapeCollection.PrimHasNoCuts(pbs)) | ||
843 | { | ||
844 | maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | // setup and do convex hull conversion | ||
849 | m_hulls = new List<ConvexResult>(); | ||
850 | DecompDesc dcomp = new DecompDesc(); | ||
851 | dcomp.mIndices = convIndices; | ||
852 | dcomp.mVertices = convVertices; | ||
853 | dcomp.mDepth = maxDepthSplit; | ||
854 | dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; | ||
855 | dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; | ||
856 | dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; | ||
857 | dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; | ||
858 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
859 | // create the hull into the _hulls variable | ||
860 | convexBuilder.process(dcomp); | ||
861 | |||
862 | physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", | ||
863 | BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); | ||
864 | |||
865 | // Convert the vertices and indices for passing to unmanaged. | ||
866 | // The hull information is passed as a large floating point array. | ||
867 | // The format is: | ||
868 | // convHulls[0] = number of hulls | ||
869 | // convHulls[1] = number of vertices in first hull | ||
870 | // convHulls[2] = hull centroid X coordinate | ||
871 | // convHulls[3] = hull centroid Y coordinate | ||
872 | // convHulls[4] = hull centroid Z coordinate | ||
873 | // convHulls[5] = first hull vertex X | ||
874 | // convHulls[6] = first hull vertex Y | ||
875 | // convHulls[7] = first hull vertex Z | ||
876 | // convHulls[8] = second hull vertex X | ||
877 | // ... | ||
878 | // convHulls[n] = number of vertices in second hull | ||
879 | // convHulls[n+1] = second hull centroid X coordinate | ||
880 | // ... | ||
881 | // | ||
882 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
883 | // data structures that do not need to be converted in order to pass to Bullet. | ||
884 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
885 | int hullCount = m_hulls.Count; | ||
886 | int totalVertices = 1; // include one for the count of the hulls | ||
887 | foreach (ConvexResult cr in m_hulls) | ||
888 | { | ||
889 | totalVertices += 4; // add four for the vertex count and centroid | ||
890 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
891 | } | ||
892 | float[] convHulls = new float[totalVertices]; | ||
893 | |||
894 | convHulls[0] = (float)hullCount; | ||
895 | int jj = 1; | ||
896 | foreach (ConvexResult cr in m_hulls) | ||
897 | { | ||
898 | // copy vertices for index access | ||
899 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
900 | int kk = 0; | ||
901 | foreach (float3 ff in cr.HullVertices) | ||
902 | { | ||
903 | verts[kk++] = ff; | ||
904 | } | ||
905 | |||
906 | // add to the array one hull's worth of data | ||
907 | convHulls[jj++] = cr.HullIndices.Count; | ||
908 | convHulls[jj++] = 0f; // centroid x,y,z | ||
909 | convHulls[jj++] = 0f; | ||
910 | convHulls[jj++] = 0f; | ||
911 | foreach (int ind in cr.HullIndices) | ||
912 | { | ||
913 | convHulls[jj++] = verts[ind].x; | ||
914 | convHulls[jj++] = verts[ind].y; | ||
915 | convHulls[jj++] = verts[ind].z; | ||
916 | } | ||
917 | } | ||
918 | // create the hull data structure in Bullet | ||
919 | newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); | ||
920 | } | ||
921 | newShape.shapeKey = newHullKey; | ||
922 | return newShape; | ||
923 | } | ||
924 | // Callback from convex hull creater with a newly created hull. | ||
925 | // Just add it to our collection of hulls for this shape. | ||
926 | private void HullReturn(ConvexResult result) | ||
927 | { | ||
928 | m_hulls.Add(result); | ||
929 | return; | ||
930 | } | ||
931 | // Loop through all the known hulls and return the description based on the physical address. | ||
932 | public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull) | ||
933 | { | ||
934 | bool ret = false; | ||
935 | BSShapeHull foundDesc = null; | ||
936 | lock (Hulls) | ||
937 | { | ||
938 | foreach (BSShapeHull sh in Hulls.Values) | ||
939 | { | ||
940 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
941 | { | ||
942 | foundDesc = sh; | ||
943 | ret = true; | ||
944 | break; | ||
945 | } | ||
946 | |||
947 | } | ||
948 | } | ||
949 | outHull = foundDesc; | ||
950 | return ret; | ||
951 | } | ||
952 | } | ||
953 | |||
954 | // ============================================================================================================ | ||
955 | // BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate | ||
956 | // meshes. Used by BulletSim for complex shapes like linksets. | ||
957 | public class BSShapeCompound : BSShape | ||
958 | { | ||
959 | private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; | ||
960 | public static Dictionary<string, BSShapeCompound> CompoundShapes = new Dictionary<string, BSShapeCompound>(); | ||
961 | |||
962 | public BSShapeCompound(BulletShape pShape) : base(pShape) | ||
963 | { | ||
964 | } | ||
965 | public static BSShape GetReference(BSScene physicsScene) | ||
966 | { | ||
967 | // Base compound shapes are not shared so this returns a raw shape. | ||
968 | // A built compound shape can be reused in linksets. | ||
969 | BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene)); | ||
970 | CompoundShapes.Add(ret.AddrString, ret); | ||
971 | return ret; | ||
972 | } | ||
973 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
974 | { | ||
975 | // Calling this reference means we want another handle to an existing compound shape | ||
976 | // (usually linksets) so return this copy. | ||
977 | IncrementReference(); | ||
978 | return this; | ||
979 | } | ||
980 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
981 | public override void Dereference(BSScene physicsScene) | ||
982 | { | ||
983 | lock (physShapeInfo) | ||
984 | { | ||
985 | this.DecrementReference(); | ||
986 | physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
987 | if (referenceCount <= 0) | ||
988 | { | ||
989 | if (!physicsScene.PE.IsCompound(physShapeInfo)) | ||
990 | { | ||
991 | // Failed the sanity check!! | ||
992 | physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
993 | LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
994 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
995 | BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
996 | return; | ||
997 | } | ||
998 | |||
999 | int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); | ||
1000 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", | ||
1001 | BSScene.DetailLogZero, physShapeInfo, numChildren); | ||
1002 | |||
1003 | // Loop through all the children dereferencing each. | ||
1004 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
1005 | { | ||
1006 | BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); | ||
1007 | DereferenceAnonCollisionShape(physicsScene, childShape); | ||
1008 | } | ||
1009 | |||
1010 | lock (CompoundShapes) | ||
1011 | CompoundShapes.Remove(physShapeInfo.AddrString); | ||
1012 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | ||
1013 | } | ||
1014 | } | ||
1015 | } | ||
1016 | public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound) | ||
1017 | { | ||
1018 | lock (CompoundShapes) | ||
1019 | { | ||
1020 | string addr = pShape.AddrString; | ||
1021 | return CompoundShapes.TryGetValue(addr, out outCompound); | ||
1022 | } | ||
1023 | } | ||
1024 | private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) | ||
1025 | { | ||
1026 | BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); | ||
1027 | return cShape; | ||
1028 | } | ||
1029 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
1030 | // Figure out type and call the correct dereference routine. | ||
1031 | // Called at taint-time. | ||
1032 | private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) | ||
1033 | { | ||
1034 | // TODO: figure a better way to go through all the shape types and find a possible instance. | ||
1035 | physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}", | ||
1036 | BSScene.DetailLogZero, pShape); | ||
1037 | BSShapeMesh meshDesc; | ||
1038 | if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) | ||
1039 | { | ||
1040 | meshDesc.Dereference(physicsScene); | ||
1041 | // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape); | ||
1042 | } | ||
1043 | else | ||
1044 | { | ||
1045 | BSShapeHull hullDesc; | ||
1046 | if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) | ||
1047 | { | ||
1048 | hullDesc.Dereference(physicsScene); | ||
1049 | // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape); | ||
1050 | } | ||
1051 | else | ||
1052 | { | ||
1053 | BSShapeConvexHull chullDesc; | ||
1054 | if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc)) | ||
1055 | { | ||
1056 | chullDesc.Dereference(physicsScene); | ||
1057 | // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape); | ||
1058 | } | ||
1059 | else | ||
1060 | { | ||
1061 | BSShapeGImpact gImpactDesc; | ||
1062 | if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc)) | ||
1063 | { | ||
1064 | gImpactDesc.Dereference(physicsScene); | ||
1065 | // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape); | ||
1066 | } | ||
1067 | else | ||
1068 | { | ||
1069 | // Didn't find it in the lists of specific types. It could be compound. | ||
1070 | BSShapeCompound compoundDesc; | ||
1071 | if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc)) | ||
1072 | { | ||
1073 | compoundDesc.Dereference(physicsScene); | ||
1074 | // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape); | ||
1075 | } | ||
1076 | else | ||
1077 | { | ||
1078 | // If none of the above, maybe it is a simple native shape. | ||
1079 | if (physicsScene.PE.IsNativeShape(pShape)) | ||
1080 | { | ||
1081 | // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape); | ||
1082 | BSShapeNative nativeShape = new BSShapeNative(pShape); | ||
1083 | nativeShape.Dereference(physicsScene); | ||
1084 | } | ||
1085 | else | ||
1086 | { | ||
1087 | physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}", | ||
1088 | LogHeader, pShape); | ||
1089 | } | ||
1090 | } | ||
1091 | } | ||
1092 | } | ||
1093 | } | ||
1094 | } | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | // ============================================================================================================ | ||
1099 | // BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex | ||
1100 | // hull shapes. This is used for simple prims that are convex and thus can be made into a simple | ||
1101 | // collision shape (a single hull). More complex physical shapes will be BSShapeHull's. | ||
1102 | public class BSShapeConvexHull : BSShape | ||
1103 | { | ||
1104 | #pragma warning disable 414 | ||
1105 | private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; | ||
1106 | #pragma warning restore 414 | ||
1107 | |||
1108 | public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>(); | ||
1109 | |||
1110 | public BSShapeConvexHull(BulletShape pShape) : base(pShape) | ||
1111 | { | ||
1112 | } | ||
1113 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
1114 | { | ||
1115 | float lod; | ||
1116 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
1117 | |||
1118 | physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}", | ||
1119 | prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); | ||
1120 | |||
1121 | BSShapeConvexHull retConvexHull = null; | ||
1122 | lock (ConvexHulls) | ||
1123 | { | ||
1124 | if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) | ||
1125 | { | ||
1126 | // The mesh has already been created. Return a new reference to same. | ||
1127 | retConvexHull.IncrementReference(); | ||
1128 | } | ||
1129 | else | ||
1130 | { | ||
1131 | retConvexHull = new BSShapeConvexHull(new BulletShape()); | ||
1132 | BulletShape convexShape = null; | ||
1133 | |||
1134 | // Get a handle to a mesh to build the hull from | ||
1135 | BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); | ||
1136 | if (baseMesh.physShapeInfo.isNativeShape) | ||
1137 | { | ||
1138 | // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. | ||
1139 | // In the short term, we return the native shape and a later ForceBodyShapeRebuild should | ||
1140 | // get back to this code with a buildable mesh. | ||
1141 | // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? | ||
1142 | convexShape = baseMesh.physShapeInfo; | ||
1143 | } | ||
1144 | else | ||
1145 | { | ||
1146 | convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); | ||
1147 | convexShape.shapeKey = newMeshKey; | ||
1148 | ConvexHulls.Add(convexShape.shapeKey, retConvexHull); | ||
1149 | physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}", | ||
1150 | BSScene.DetailLogZero, convexShape); | ||
1151 | } | ||
1152 | |||
1153 | // Done with the base mesh | ||
1154 | baseMesh.Dereference(physicsScene); | ||
1155 | |||
1156 | retConvexHull.physShapeInfo = convexShape; | ||
1157 | } | ||
1158 | } | ||
1159 | return retConvexHull; | ||
1160 | } | ||
1161 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
1162 | { | ||
1163 | // Calling this reference means we want another handle to an existing shape | ||
1164 | // (usually linksets) so return this copy. | ||
1165 | IncrementReference(); | ||
1166 | return this; | ||
1167 | } | ||
1168 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
1169 | public override void Dereference(BSScene physicsScene) | ||
1170 | { | ||
1171 | lock (ConvexHulls) | ||
1172 | { | ||
1173 | this.DecrementReference(); | ||
1174 | physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
1175 | // TODO: schedule aging and destruction of unused meshes. | ||
1176 | } | ||
1177 | } | ||
1178 | // Loop through all the known hulls and return the description based on the physical address. | ||
1179 | public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull) | ||
1180 | { | ||
1181 | bool ret = false; | ||
1182 | BSShapeConvexHull foundDesc = null; | ||
1183 | lock (ConvexHulls) | ||
1184 | { | ||
1185 | foreach (BSShapeConvexHull sh in ConvexHulls.Values) | ||
1186 | { | ||
1187 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
1188 | { | ||
1189 | foundDesc = sh; | ||
1190 | ret = true; | ||
1191 | break; | ||
1192 | } | ||
1193 | |||
1194 | } | ||
1195 | } | ||
1196 | outHull = foundDesc; | ||
1197 | return ret; | ||
1198 | } | ||
1199 | } | ||
1200 | // ============================================================================================================ | ||
1201 | // BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that | ||
1202 | // can handle concave as well as convex shapes. Much slower computationally but creates smoother | ||
1203 | // shapes than multiple convex hull approximations. | ||
1204 | public class BSShapeGImpact : BSShape | ||
1205 | { | ||
1206 | #pragma warning disable 414 | ||
1207 | private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]"; | ||
1208 | #pragma warning restore 414 | ||
1209 | |||
1210 | public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>(); | ||
1211 | |||
1212 | public BSShapeGImpact(BulletShape pShape) : base(pShape) | ||
1213 | { | ||
1214 | } | ||
1215 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
1216 | { | ||
1217 | float lod; | ||
1218 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
1219 | |||
1220 | physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}", | ||
1221 | prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); | ||
1222 | |||
1223 | BSShapeGImpact retGImpact = null; | ||
1224 | lock (GImpacts) | ||
1225 | { | ||
1226 | if (GImpacts.TryGetValue(newMeshKey, out retGImpact)) | ||
1227 | { | ||
1228 | // The mesh has already been created. Return a new reference to same. | ||
1229 | retGImpact.IncrementReference(); | ||
1230 | } | ||
1231 | else | ||
1232 | { | ||
1233 | retGImpact = new BSShapeGImpact(new BulletShape()); | ||
1234 | BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
1235 | |||
1236 | // Check to see if mesh was created (might require an asset). | ||
1237 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
1238 | newShape.shapeKey = newMeshKey; | ||
1239 | if (!newShape.isNativeShape || prim.AssetFailed()) | ||
1240 | { | ||
1241 | // If a mesh was what was created, remember the built shape for later sharing. | ||
1242 | // Also note that if meshing failed we put it in the mesh list as there is nothing | ||
1243 | // else to do about the mesh. | ||
1244 | GImpacts.Add(newMeshKey, retGImpact); | ||
1245 | } | ||
1246 | |||
1247 | retGImpact.physShapeInfo = newShape; | ||
1248 | } | ||
1249 | } | ||
1250 | return retGImpact; | ||
1251 | } | ||
1252 | |||
1253 | private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
1254 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
1255 | { | ||
1256 | return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, | ||
1257 | (w, iC, i, vC, v) => | ||
1258 | { | ||
1259 | shapeInfo.Vertices = vC; | ||
1260 | return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v); | ||
1261 | }); | ||
1262 | } | ||
1263 | |||
1264 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
1265 | { | ||
1266 | BSShape ret = null; | ||
1267 | // If the underlying shape is native, the actual shape has not been build (waiting for asset) | ||
1268 | // and we must create a copy of the native shape since they are never shared. | ||
1269 | if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) | ||
1270 | { | ||
1271 | // TODO: decide when the native shapes should be freed. Check in Dereference? | ||
1272 | ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
1273 | } | ||
1274 | else | ||
1275 | { | ||
1276 | // Another reference to this shape is just counted. | ||
1277 | IncrementReference(); | ||
1278 | ret = this; | ||
1279 | } | ||
1280 | return ret; | ||
1281 | } | ||
1282 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
1283 | public override void Dereference(BSScene physicsScene) | ||
1284 | { | ||
1285 | lock (GImpacts) | ||
1286 | { | ||
1287 | this.DecrementReference(); | ||
1288 | physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
1289 | // TODO: schedule aging and destruction of unused meshes. | ||
1290 | } | ||
1291 | } | ||
1292 | // Loop through all the known hulls and return the description based on the physical address. | ||
1293 | public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull) | ||
1294 | { | ||
1295 | bool ret = false; | ||
1296 | BSShapeGImpact foundDesc = null; | ||
1297 | lock (GImpacts) | ||
1298 | { | ||
1299 | foreach (BSShapeGImpact sh in GImpacts.Values) | ||
1300 | { | ||
1301 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
1302 | { | ||
1303 | foundDesc = sh; | ||
1304 | ret = true; | ||
1305 | break; | ||
1306 | } | ||
1307 | |||
1308 | } | ||
1309 | } | ||
1310 | outHull = foundDesc; | ||
1311 | return ret; | ||
1312 | } | ||
1313 | } | ||
1314 | |||
1315 | // ============================================================================================================ | ||
1316 | // BSShapeAvatar is a specialized mesh shape for avatars. | ||
1317 | public class BSShapeAvatar : BSShape | ||
1318 | { | ||
1319 | #pragma warning disable 414 | ||
1320 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; | ||
1321 | #pragma warning restore 414 | ||
1322 | |||
1323 | public BSShapeAvatar() | ||
1324 | : base() | ||
1325 | { | ||
1326 | } | ||
1327 | public static BSShape GetReference(BSPhysObject prim) | ||
1328 | { | ||
1329 | return new BSShapeNull(); | ||
1330 | } | ||
1331 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
1332 | { | ||
1333 | return new BSShapeNull(); | ||
1334 | } | ||
1335 | public override void Dereference(BSScene physicsScene) { } | ||
1336 | |||
1337 | // From the front: | ||
1338 | // A---A | ||
1339 | // / \ | ||
1340 | // B-------B | ||
1341 | // / \ +Z | ||
1342 | // C-----------C | | ||
1343 | // \ / -Y --+-- +Y | ||
1344 | // \ / | | ||
1345 | // \ / -Z | ||
1346 | // D-----D | ||
1347 | // \ / | ||
1348 | // E-E | ||
1349 | |||
1350 | // From the top A and E are just lines. | ||
1351 | // B, C and D are hexagons: | ||
1352 | // | ||
1353 | // C1--C2 +X | ||
1354 | // / \ | | ||
1355 | // C0 C3 -Y --+-- +Y | ||
1356 | // \ / | | ||
1357 | // C5--C4 -X | ||
1358 | |||
1359 | // Zero goes directly through the middle so the offsets are from that middle axis | ||
1360 | // and up and down from a middle horizon (A and E are the same distance from the zero). | ||
1361 | // The height, width and depth is one. All scaling is done by the simulator. | ||
1362 | |||
1363 | // Z component -- how far the level is from the middle zero | ||
1364 | private const float Aup = 0.5f; | ||
1365 | private const float Bup = 0.4f; | ||
1366 | private const float Cup = 0.3f; | ||
1367 | private const float Dup = -0.4f; | ||
1368 | private const float Eup = -0.5f; | ||
1369 | |||
1370 | // Y component -- distance from center to x0 and x3 | ||
1371 | private const float Awid = 0.25f; | ||
1372 | private const float Bwid = 0.3f; | ||
1373 | private const float Cwid = 0.5f; | ||
1374 | private const float Dwid = 0.3f; | ||
1375 | private const float Ewid = 0.2f; | ||
1376 | |||
1377 | // Y component -- distance from center to x1, x2, x4 and x5 | ||
1378 | private const float Afwid = 0.0f; | ||
1379 | private const float Bfwid = 0.2f; | ||
1380 | private const float Cfwid = 0.4f; | ||
1381 | private const float Dfwid = 0.2f; | ||
1382 | private const float Efwid = 0.0f; | ||
1383 | |||
1384 | // X component -- distance from zero to the front or back of a level | ||
1385 | private const float Adep = 0f; | ||
1386 | private const float Bdep = 0.3f; | ||
1387 | private const float Cdep = 0.5f; | ||
1388 | private const float Ddep = 0.2f; | ||
1389 | private const float Edep = 0f; | ||
1390 | |||
1391 | private OMV.Vector3[] avatarVertices = { | ||
1392 | new OMV.Vector3( 0.0f, -Awid, Aup), // A0 | ||
1393 | new OMV.Vector3( 0.0f, +Awid, Aup), // A3 | ||
1394 | |||
1395 | new OMV.Vector3( 0.0f, -Bwid, Bup), // B0 | ||
1396 | new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1 | ||
1397 | new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2 | ||
1398 | new OMV.Vector3( 0.0f, +Bwid, Bup), // B3 | ||
1399 | new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4 | ||
1400 | new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5 | ||
1401 | |||
1402 | new OMV.Vector3( 0.0f, -Cwid, Cup), // C0 | ||
1403 | new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1 | ||
1404 | new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2 | ||
1405 | new OMV.Vector3( 0.0f, +Cwid, Cup), // C3 | ||
1406 | new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4 | ||
1407 | new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5 | ||
1408 | |||
1409 | new OMV.Vector3( 0.0f, -Dwid, Dup), // D0 | ||
1410 | new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1 | ||
1411 | new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2 | ||
1412 | new OMV.Vector3( 0.0f, +Dwid, Dup), // D3 | ||
1413 | new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4 | ||
1414 | new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5 | ||
1415 | |||
1416 | new OMV.Vector3( 0.0f, -Ewid, Eup), // E0 | ||
1417 | new OMV.Vector3( 0.0f, +Ewid, Eup), // E3 | ||
1418 | }; | ||
1419 | |||
1420 | // Offsets of the vertices in the vertices array | ||
1421 | private enum Ind : int | ||
1422 | { | ||
1423 | A0, A3, | ||
1424 | B0, B1, B2, B3, B4, B5, | ||
1425 | C0, C1, C2, C3, C4, C5, | ||
1426 | D0, D1, D2, D3, D4, D5, | ||
1427 | E0, E3 | ||
1428 | } | ||
1429 | |||
1430 | // Comments specify trianges and quads in clockwise direction | ||
1431 | private Ind[] avatarIndices = { | ||
1432 | Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1 | ||
1433 | Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3 | ||
1434 | Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3 | ||
1435 | Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4 | ||
1436 | Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0 | ||
1437 | Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0 | ||
1438 | |||
1439 | Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1 | ||
1440 | Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2 | ||
1441 | Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3 | ||
1442 | Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4 | ||
1443 | Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5 | ||
1444 | Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0 | ||
1445 | |||
1446 | Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1 | ||
1447 | Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2 | ||
1448 | Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3 | ||
1449 | Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4 | ||
1450 | Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5 | ||
1451 | Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0 | ||
1452 | |||
1453 | Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1 | ||
1454 | Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3 | ||
1455 | Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3 | ||
1456 | Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4 | ||
1457 | Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0 | ||
1458 | Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0 | ||
1459 | |||
1460 | }; | ||
1461 | |||
1462 | } | ||
1463 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs new file mode 100755 index 0000000..d70b2fb --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs | |||
@@ -0,0 +1,170 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework; | ||
33 | using OpenSim.Region.CoreModules; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | using Nini.Config; | ||
37 | using log4net; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
42 | { | ||
43 | public sealed class BSTerrainHeightmap : BSTerrainPhys | ||
44 | { | ||
45 | static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; | ||
46 | |||
47 | BulletHMapInfo m_mapInfo = null; | ||
48 | |||
49 | // Constructor to build a default, flat heightmap terrain. | ||
50 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) | ||
51 | : base(physicsScene, regionBase, id) | ||
52 | { | ||
53 | Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE); | ||
54 | Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION); | ||
55 | int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; | ||
56 | float[] initialMap = new float[totalHeights]; | ||
57 | for (int ii = 0; ii < totalHeights; ii++) | ||
58 | { | ||
59 | initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; | ||
60 | } | ||
61 | m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y); | ||
62 | m_mapInfo.minCoords = minTerrainCoords; | ||
63 | m_mapInfo.maxCoords = maxTerrainCoords; | ||
64 | m_mapInfo.terrainRegionBase = TerrainBase; | ||
65 | // Don't have to free any previous since we just got here. | ||
66 | BuildHeightmapTerrain(); | ||
67 | } | ||
68 | |||
69 | // This minCoords and maxCoords passed in give the size of the terrain (min and max Z | ||
70 | // are the high and low points of the heightmap). | ||
71 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, | ||
72 | Vector3 minCoords, Vector3 maxCoords) | ||
73 | : base(physicsScene, regionBase, id) | ||
74 | { | ||
75 | m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y); | ||
76 | m_mapInfo.minCoords = minCoords; | ||
77 | m_mapInfo.maxCoords = maxCoords; | ||
78 | m_mapInfo.minZ = minCoords.Z; | ||
79 | m_mapInfo.maxZ = maxCoords.Z; | ||
80 | m_mapInfo.terrainRegionBase = TerrainBase; | ||
81 | |||
82 | // Don't have to free any previous since we just got here. | ||
83 | BuildHeightmapTerrain(); | ||
84 | } | ||
85 | |||
86 | public override void Dispose() | ||
87 | { | ||
88 | ReleaseHeightMapTerrain(); | ||
89 | } | ||
90 | |||
91 | // Using the information in m_mapInfo, create the physical representation of the heightmap. | ||
92 | private void BuildHeightmapTerrain() | ||
93 | { | ||
94 | // Create the terrain shape from the mapInfo | ||
95 | m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID, | ||
96 | new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, | ||
97 | m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); | ||
98 | |||
99 | |||
100 | // The terrain object initial position is at the center of the object | ||
101 | Vector3 centerPos; | ||
102 | centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f); | ||
103 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); | ||
104 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); | ||
105 | |||
106 | m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, | ||
107 | m_mapInfo.ID, centerPos, Quaternion.Identity); | ||
108 | |||
109 | // Set current terrain attributes | ||
110 | m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); | ||
111 | m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); | ||
112 | m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); | ||
113 | m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); | ||
114 | |||
115 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; | ||
116 | |||
117 | // Return the new terrain to the world of physical objects | ||
118 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody); | ||
119 | |||
120 | // redo its bounding box now that it is in the world | ||
121 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody); | ||
122 | |||
123 | // Make it so the terrain will not move or be considered for movement. | ||
124 | m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); | ||
125 | |||
126 | return; | ||
127 | } | ||
128 | |||
129 | // If there is information in m_mapInfo pointing to physical structures, release same. | ||
130 | private void ReleaseHeightMapTerrain() | ||
131 | { | ||
132 | if (m_mapInfo != null) | ||
133 | { | ||
134 | if (m_mapInfo.terrainBody.HasPhysicalBody) | ||
135 | { | ||
136 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody); | ||
137 | // Frees both the body and the shape. | ||
138 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody); | ||
139 | } | ||
140 | } | ||
141 | m_mapInfo = null; | ||
142 | } | ||
143 | |||
144 | // The passed position is relative to the base of the region. | ||
145 | public override float GetTerrainHeightAtXYZ(Vector3 pos) | ||
146 | { | ||
147 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
148 | |||
149 | int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X; | ||
150 | try | ||
151 | { | ||
152 | ret = m_mapInfo.heightMap[mapIndex]; | ||
153 | } | ||
154 | catch | ||
155 | { | ||
156 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | ||
157 | m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", | ||
158 | LogHeader, m_mapInfo.terrainRegionBase, pos); | ||
159 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
160 | } | ||
161 | return ret; | ||
162 | } | ||
163 | |||
164 | // The passed position is relative to the base of the region. | ||
165 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
166 | { | ||
167 | return m_physicsScene.SimpleWaterLevel; | ||
168 | } | ||
169 | } | ||
170 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs new file mode 100755 index 0000000..50f917a --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs | |||
@@ -0,0 +1,585 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework; | ||
33 | using OpenSim.Region.CoreModules; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | using Nini.Config; | ||
37 | using log4net; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
42 | { | ||
43 | |||
44 | // The physical implementation of the terrain is wrapped in this class. | ||
45 | public abstract class BSTerrainPhys : IDisposable | ||
46 | { | ||
47 | public enum TerrainImplementation | ||
48 | { | ||
49 | Heightmap = 0, | ||
50 | Mesh = 1 | ||
51 | } | ||
52 | |||
53 | protected BSScene m_physicsScene { get; private set; } | ||
54 | // Base of the region in world coordinates. Coordinates inside the region are relative to this. | ||
55 | public Vector3 TerrainBase { get; private set; } | ||
56 | public uint ID { get; private set; } | ||
57 | |||
58 | public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) | ||
59 | { | ||
60 | m_physicsScene = physicsScene; | ||
61 | TerrainBase = regionBase; | ||
62 | ID = id; | ||
63 | } | ||
64 | public abstract void Dispose(); | ||
65 | public abstract float GetTerrainHeightAtXYZ(Vector3 pos); | ||
66 | public abstract float GetWaterLevelAtXYZ(Vector3 pos); | ||
67 | } | ||
68 | |||
69 | // ========================================================================================== | ||
70 | public sealed class BSTerrainManager : IDisposable | ||
71 | { | ||
72 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; | ||
73 | |||
74 | // These height values are fractional so the odd values will be | ||
75 | // noticable when debugging. | ||
76 | public const float HEIGHT_INITIALIZATION = 24.987f; | ||
77 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; | ||
78 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; | ||
79 | public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; | ||
80 | |||
81 | // If the min and max height are equal, we reduce the min by this | ||
82 | // amount to make sure that a bounding box is built for the terrain. | ||
83 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; | ||
84 | |||
85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. | ||
86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
87 | |||
88 | // The scene that I am part of | ||
89 | private BSScene m_physicsScene { get; set; } | ||
90 | |||
91 | // The ground plane created to keep thing from falling to infinity. | ||
92 | private BulletBody m_groundPlane; | ||
93 | |||
94 | // If doing mega-regions, if we're region zero we will be managing multiple | ||
95 | // region terrains since region zero does the physics for the whole mega-region. | ||
96 | private Dictionary<Vector3, BSTerrainPhys> m_terrains; | ||
97 | |||
98 | // Flags used to know when to recalculate the height. | ||
99 | private bool m_terrainModified = false; | ||
100 | |||
101 | // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. | ||
102 | // This is incremented before assigning to new region so it is the last ID allocated. | ||
103 | private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; | ||
104 | public uint HighestTerrainID { get {return m_terrainCount; } } | ||
105 | |||
106 | // If doing mega-regions, this holds our offset from region zero of | ||
107 | // the mega-regions. "parentScene" points to the PhysicsScene of region zero. | ||
108 | private Vector3 m_worldOffset; | ||
109 | // If the parent region (region 0), this is the extent of the combined regions | ||
110 | // relative to the origin of region zero | ||
111 | private Vector3 m_worldMax; | ||
112 | private PhysicsScene MegaRegionParentPhysicsScene { get; set; } | ||
113 | |||
114 | public BSTerrainManager(BSScene physicsScene, Vector3 regionSize) | ||
115 | { | ||
116 | m_physicsScene = physicsScene; | ||
117 | DefaultRegionSize = regionSize; | ||
118 | |||
119 | m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); | ||
120 | |||
121 | // Assume one region of default size | ||
122 | m_worldOffset = Vector3.Zero; | ||
123 | m_worldMax = new Vector3(DefaultRegionSize); | ||
124 | MegaRegionParentPhysicsScene = null; | ||
125 | } | ||
126 | |||
127 | public void Dispose() | ||
128 | { | ||
129 | ReleaseGroundPlaneAndTerrain(); | ||
130 | } | ||
131 | |||
132 | // Create the initial instance of terrain and the underlying ground plane. | ||
133 | // This is called from the initialization routine so we presume it is | ||
134 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | ||
135 | public void CreateInitialGroundPlaneAndTerrain() | ||
136 | { | ||
137 | DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); | ||
138 | // The ground plane is here to catch things that are trying to drop to negative infinity | ||
139 | BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); | ||
140 | Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane); | ||
141 | m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, | ||
142 | BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity); | ||
143 | |||
144 | // Everything collides with the ground plane. | ||
145 | m_groundPlane.collisionType = CollisionType.Groundplane; | ||
146 | |||
147 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); | ||
148 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane); | ||
149 | |||
150 | // Ground plane does not move | ||
151 | m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); | ||
152 | |||
153 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | ||
154 | lock (m_terrains) | ||
155 | { | ||
156 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | ||
157 | m_terrains.Add(Vector3.Zero, initialTerrain); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | // Release all the terrain structures we might have allocated | ||
162 | public void ReleaseGroundPlaneAndTerrain() | ||
163 | { | ||
164 | DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); | ||
165 | if (m_groundPlane.HasPhysicalBody) | ||
166 | { | ||
167 | if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane)) | ||
168 | { | ||
169 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane); | ||
170 | } | ||
171 | m_groundPlane.Clear(); | ||
172 | } | ||
173 | |||
174 | ReleaseTerrain(); | ||
175 | } | ||
176 | |||
177 | // Release all the terrain we have allocated | ||
178 | public void ReleaseTerrain() | ||
179 | { | ||
180 | lock (m_terrains) | ||
181 | { | ||
182 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) | ||
183 | { | ||
184 | kvp.Value.Dispose(); | ||
185 | } | ||
186 | m_terrains.Clear(); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | // The simulator wants to set a new heightmap for the terrain. | ||
191 | public void SetTerrain(float[] heightMap) { | ||
192 | float[] localHeightMap = heightMap; | ||
193 | // If there are multiple requests for changes to the same terrain between ticks, | ||
194 | // only do that last one. | ||
195 | m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | ||
196 | { | ||
197 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | ||
198 | { | ||
199 | // If a child of a mega-region, we shouldn't have any terrain allocated for us | ||
200 | ReleaseGroundPlaneAndTerrain(); | ||
201 | // If doing the mega-prim stuff and we are the child of the zero region, | ||
202 | // the terrain is added to our parent | ||
203 | if (MegaRegionParentPhysicsScene is BSScene) | ||
204 | { | ||
205 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); | ||
206 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain( | ||
207 | BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); | ||
208 | } | ||
209 | } | ||
210 | else | ||
211 | { | ||
212 | // If not doing the mega-prim thing, just change the terrain | ||
213 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); | ||
214 | |||
215 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); | ||
216 | } | ||
217 | }); | ||
218 | } | ||
219 | |||
220 | // Another region is calling this region and passing a terrain. | ||
221 | // A region that is not the mega-region root will pass its terrain to the root region so the root region | ||
222 | // physics engine will have all the terrains. | ||
223 | private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | ||
224 | { | ||
225 | // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. | ||
226 | m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() | ||
227 | { | ||
228 | UpdateTerrain(id, heightMap, minCoords, maxCoords); | ||
229 | }); | ||
230 | } | ||
231 | |||
232 | // If called for terrain has has not been previously allocated, a new terrain will be built | ||
233 | // based on the passed information. The 'id' should be either the terrain id or | ||
234 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. | ||
235 | // The latter feature is for creating child terrains for mega-regions. | ||
236 | // If there is an existing terrain body, a new | ||
237 | // terrain shape is created and added to the body. | ||
238 | // This call is most often used to update the heightMap and parameters of the terrain. | ||
239 | // (The above does suggest that some simplification/refactoring is in order.) | ||
240 | // Called during taint-time. | ||
241 | private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | ||
242 | { | ||
243 | // Find high and low points of passed heightmap. | ||
244 | // The min and max passed in is usually the area objects can be in (maximum | ||
245 | // object height, for instance). The terrain wants the bounding box for the | ||
246 | // terrain so replace passed min and max Z with the actual terrain min/max Z. | ||
247 | float minZ = float.MaxValue; | ||
248 | float maxZ = float.MinValue; | ||
249 | foreach (float height in heightMap) | ||
250 | { | ||
251 | if (height < minZ) minZ = height; | ||
252 | if (height > maxZ) maxZ = height; | ||
253 | } | ||
254 | if (minZ == maxZ) | ||
255 | { | ||
256 | // If min and max are the same, reduce min a little bit so a good bounding box is created. | ||
257 | minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE; | ||
258 | } | ||
259 | minCoords.Z = minZ; | ||
260 | maxCoords.Z = maxZ; | ||
261 | |||
262 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}", | ||
263 | BSScene.DetailLogZero, id, minCoords, maxCoords); | ||
264 | |||
265 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); | ||
266 | |||
267 | lock (m_terrains) | ||
268 | { | ||
269 | BSTerrainPhys terrainPhys; | ||
270 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | ||
271 | { | ||
272 | // There is already a terrain in this spot. Free the old and build the new. | ||
273 | DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | ||
274 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords); | ||
275 | |||
276 | // Remove old terrain from the collection | ||
277 | m_terrains.Remove(terrainRegionBase); | ||
278 | // Release any physical memory it may be using. | ||
279 | terrainPhys.Dispose(); | ||
280 | |||
281 | if (MegaRegionParentPhysicsScene == null) | ||
282 | { | ||
283 | // This terrain is not part of the mega-region scheme. Create vanilla terrain. | ||
284 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | ||
285 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | ||
286 | |||
287 | m_terrainModified = true; | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | // It's possible that Combine() was called after this code was queued. | ||
292 | // If we are a child of combined regions, we don't create any terrain for us. | ||
293 | DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); | ||
294 | |||
295 | // Get rid of any terrain that may have been allocated for us. | ||
296 | ReleaseGroundPlaneAndTerrain(); | ||
297 | |||
298 | // I hate doing this, but just bail | ||
299 | return; | ||
300 | } | ||
301 | } | ||
302 | else | ||
303 | { | ||
304 | // We don't know about this terrain so either we are creating a new terrain or | ||
305 | // our mega-prim child is giving us a new terrain to add to the phys world | ||
306 | |||
307 | // if this is a child terrain, calculate a unique terrain id | ||
308 | uint newTerrainID = id; | ||
309 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
310 | newTerrainID = ++m_terrainCount; | ||
311 | |||
312 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", | ||
313 | BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); | ||
314 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | ||
315 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | ||
316 | |||
317 | m_terrainModified = true; | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | // TODO: redo terrain implementation selection to allow other base types than heightMap. | ||
323 | private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | ||
324 | { | ||
325 | m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", | ||
326 | LogHeader, m_physicsScene.RegionName, terrainRegionBase, | ||
327 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); | ||
328 | BSTerrainPhys newTerrainPhys = null; | ||
329 | switch ((int)BSParam.TerrainImplementation) | ||
330 | { | ||
331 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | ||
332 | newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id, | ||
333 | heightMap, minCoords, maxCoords); | ||
334 | break; | ||
335 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: | ||
336 | newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id, | ||
337 | heightMap, minCoords, maxCoords); | ||
338 | break; | ||
339 | default: | ||
340 | m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", | ||
341 | LogHeader, | ||
342 | (int)BSParam.TerrainImplementation, | ||
343 | BSParam.TerrainImplementation, | ||
344 | m_physicsScene.RegionName, terrainRegionBase); | ||
345 | break; | ||
346 | } | ||
347 | return newTerrainPhys; | ||
348 | } | ||
349 | |||
350 | // Return 'true' of this position is somewhere in known physical terrain space | ||
351 | public bool IsWithinKnownTerrain(Vector3 pos) | ||
352 | { | ||
353 | Vector3 terrainBaseXYZ; | ||
354 | BSTerrainPhys physTerrain; | ||
355 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); | ||
356 | } | ||
357 | |||
358 | // Return a new position that is over known terrain if the position is outside our terrain. | ||
359 | public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) | ||
360 | { | ||
361 | float edgeEpsilon = 0.1f; | ||
362 | |||
363 | Vector3 ret = pPos; | ||
364 | |||
365 | // First, base addresses are never negative so correct for that possible problem. | ||
366 | if (ret.X < 0f || ret.Y < 0f) | ||
367 | { | ||
368 | ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f); | ||
369 | ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f); | ||
370 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}", | ||
371 | BSScene.DetailLogZero, pPos, ret); | ||
372 | } | ||
373 | |||
374 | // Can't do this function if we don't know about any terrain. | ||
375 | if (m_terrains.Count == 0) | ||
376 | return ret; | ||
377 | |||
378 | int loopPrevention = 10; | ||
379 | Vector3 terrainBaseXYZ; | ||
380 | BSTerrainPhys physTerrain; | ||
381 | while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) | ||
382 | { | ||
383 | // The passed position is not within a known terrain area. | ||
384 | // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region. | ||
385 | |||
386 | // Must be off the top of a region. Find an adjacent region to move into. | ||
387 | // The returned terrain is always 'lower'. That is, closer to <0,0>. | ||
388 | Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); | ||
389 | |||
390 | if (adjacentTerrainBase.X < terrainBaseXYZ.X) | ||
391 | { | ||
392 | // moving down into a new region in the X dimension. New position will be the max in the new base. | ||
393 | ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon; | ||
394 | } | ||
395 | if (adjacentTerrainBase.Y < terrainBaseXYZ.Y) | ||
396 | { | ||
397 | // moving down into a new region in the X dimension. New position will be the max in the new base. | ||
398 | ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon; | ||
399 | } | ||
400 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", | ||
401 | BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); | ||
402 | |||
403 | if (loopPrevention-- < 0f) | ||
404 | { | ||
405 | // The 'while' is a little dangerous so this prevents looping forever if the | ||
406 | // mapping of the terrains ever gets messed up (like nothing at <0,0>) or | ||
407 | // the list of terrains is in transition. | ||
408 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero); | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | // Given an X and Y, find the height of the terrain. | ||
417 | // Since we could be handling multiple terrains for a mega-region, | ||
418 | // the base of the region is calcuated assuming all regions are | ||
419 | // the same size and that is the default. | ||
420 | // Once the heightMapInfo is found, we have all the information to | ||
421 | // compute the offset into the array. | ||
422 | private float lastHeightTX = 999999f; | ||
423 | private float lastHeightTY = 999999f; | ||
424 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; | ||
425 | public float GetTerrainHeightAtXYZ(Vector3 pos) | ||
426 | { | ||
427 | float tX = pos.X; | ||
428 | float tY = pos.Y; | ||
429 | // You'd be surprized at the number of times this routine is called | ||
430 | // with the same parameters as last time. | ||
431 | if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) | ||
432 | return lastHeight; | ||
433 | m_terrainModified = false; | ||
434 | |||
435 | lastHeightTX = tX; | ||
436 | lastHeightTY = tY; | ||
437 | float ret = HEIGHT_GETHEIGHT_RET; | ||
438 | |||
439 | Vector3 terrainBaseXYZ; | ||
440 | BSTerrainPhys physTerrain; | ||
441 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) | ||
442 | { | ||
443 | ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); | ||
444 | } | ||
445 | else | ||
446 | { | ||
447 | m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | ||
448 | LogHeader, m_physicsScene.RegionName, tX, tY); | ||
449 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | ||
450 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | ||
451 | } | ||
452 | |||
453 | lastHeight = ret; | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | public float GetWaterLevelAtXYZ(Vector3 pos) | ||
458 | { | ||
459 | float ret = WATER_HEIGHT_GETHEIGHT_RET; | ||
460 | |||
461 | Vector3 terrainBaseXYZ; | ||
462 | BSTerrainPhys physTerrain; | ||
463 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) | ||
464 | { | ||
465 | ret = physTerrain.GetWaterLevelAtXYZ(pos); | ||
466 | } | ||
467 | else | ||
468 | { | ||
469 | m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", | ||
470 | LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret); | ||
471 | } | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | // Given an address, return 'true' of there is a description of that terrain and output | ||
476 | // the descriptor class and the 'base' fo the addresses therein. | ||
477 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) | ||
478 | { | ||
479 | bool ret = false; | ||
480 | |||
481 | Vector3 terrainBaseXYZ = Vector3.Zero; | ||
482 | if (pos.X < 0f || pos.Y < 0f) | ||
483 | { | ||
484 | // We don't handle negative addresses so just make up a base that will not be found. | ||
485 | terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f); | ||
486 | } | ||
487 | else | ||
488 | { | ||
489 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
490 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
491 | terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
492 | } | ||
493 | |||
494 | BSTerrainPhys physTerrain = null; | ||
495 | lock (m_terrains) | ||
496 | { | ||
497 | ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); | ||
498 | } | ||
499 | outTerrainBase = terrainBaseXYZ; | ||
500 | outPhysTerrain = physTerrain; | ||
501 | return ret; | ||
502 | } | ||
503 | |||
504 | // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than | ||
505 | // this one. Usually used to return an out of bounds object to a known place. | ||
506 | private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) | ||
507 | { | ||
508 | Vector3 ret = pTerrainBase; | ||
509 | |||
510 | // Can't do this function if we don't know about any terrain. | ||
511 | if (m_terrains.Count == 0) | ||
512 | return ret; | ||
513 | |||
514 | // Just some sanity | ||
515 | ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f); | ||
516 | ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f); | ||
517 | ret.Z = 0f; | ||
518 | |||
519 | lock (m_terrains) | ||
520 | { | ||
521 | // Once down to the <0,0> region, we have to be done. | ||
522 | while (ret.X > 0f || ret.Y > 0f) | ||
523 | { | ||
524 | if (ret.X > 0f) | ||
525 | { | ||
526 | ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X); | ||
527 | DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret); | ||
528 | if (m_terrains.ContainsKey(ret)) | ||
529 | break; | ||
530 | } | ||
531 | if (ret.Y > 0f) | ||
532 | { | ||
533 | ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y); | ||
534 | DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret); | ||
535 | if (m_terrains.ContainsKey(ret)) | ||
536 | break; | ||
537 | } | ||
538 | } | ||
539 | } | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | // Although no one seems to check this, I do support combining. | ||
545 | public bool SupportsCombining() | ||
546 | { | ||
547 | return true; | ||
548 | } | ||
549 | |||
550 | // This routine is called two ways: | ||
551 | // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum | ||
552 | // extent of the combined regions. This is to inform the parent of the size | ||
553 | // of the combined regions. | ||
554 | // and one with 'offset' as the offset of the child region to the base region, | ||
555 | // 'pScene' pointing to the parent and 'extents' of zero. This informs the | ||
556 | // child of its relative base and new parent. | ||
557 | public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) | ||
558 | { | ||
559 | m_worldOffset = offset; | ||
560 | m_worldMax = extents; | ||
561 | MegaRegionParentPhysicsScene = pScene; | ||
562 | if (pScene != null) | ||
563 | { | ||
564 | // We are a child. | ||
565 | // We want m_worldMax to be the highest coordinate of our piece of terrain. | ||
566 | m_worldMax = offset + DefaultRegionSize; | ||
567 | } | ||
568 | DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", | ||
569 | BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); | ||
570 | } | ||
571 | |||
572 | // Unhook all the combining that I know about. | ||
573 | public void UnCombine(PhysicsScene pScene) | ||
574 | { | ||
575 | // Just like ODE, we don't do anything yet. | ||
576 | DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); | ||
577 | } | ||
578 | |||
579 | |||
580 | private void DetailLog(string msg, params Object[] args) | ||
581 | { | ||
582 | m_physicsScene.PhysicsLogging.Write(msg, args); | ||
583 | } | ||
584 | } | ||
585 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs new file mode 100755 index 0000000..e4ca098 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs | |||
@@ -0,0 +1,441 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework; | ||
33 | using OpenSim.Region.CoreModules; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | using Nini.Config; | ||
37 | using log4net; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
42 | { | ||
43 | public sealed class BSTerrainMesh : BSTerrainPhys | ||
44 | { | ||
45 | static string LogHeader = "[BULLETSIM TERRAIN MESH]"; | ||
46 | |||
47 | private float[] m_savedHeightMap; | ||
48 | int m_sizeX; | ||
49 | int m_sizeY; | ||
50 | |||
51 | BulletShape m_terrainShape; | ||
52 | BulletBody m_terrainBody; | ||
53 | |||
54 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) | ||
55 | : base(physicsScene, regionBase, id) | ||
56 | { | ||
57 | } | ||
58 | |||
59 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */) | ||
60 | : base(physicsScene, regionBase, id) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | // Create terrain mesh from a heightmap. | ||
65 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, | ||
66 | Vector3 minCoords, Vector3 maxCoords) | ||
67 | : base(physicsScene, regionBase, id) | ||
68 | { | ||
69 | int indicesCount; | ||
70 | int[] indices; | ||
71 | int verticesCount; | ||
72 | float[] vertices; | ||
73 | |||
74 | m_savedHeightMap = initialMap; | ||
75 | |||
76 | m_sizeX = (int)(maxCoords.X - minCoords.X); | ||
77 | m_sizeY = (int)(maxCoords.Y - minCoords.Y); | ||
78 | |||
79 | bool meshCreationSuccess = false; | ||
80 | if (BSParam.TerrainMeshMagnification == 1) | ||
81 | { | ||
82 | // If a magnification of one, use the old routine that is tried and true. | ||
83 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene, | ||
84 | initialMap, m_sizeX, m_sizeY, // input size | ||
85 | Vector3.Zero, // base for mesh | ||
86 | out indicesCount, out indices, out verticesCount, out vertices); | ||
87 | } | ||
88 | else | ||
89 | { | ||
90 | // Other magnifications use the newer routine | ||
91 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene, | ||
92 | initialMap, m_sizeX, m_sizeY, // input size | ||
93 | BSParam.TerrainMeshMagnification, | ||
94 | physicsScene.TerrainManager.DefaultRegionSize, | ||
95 | Vector3.Zero, // base for mesh | ||
96 | out indicesCount, out indices, out verticesCount, out vertices); | ||
97 | } | ||
98 | if (!meshCreationSuccess) | ||
99 | { | ||
100 | // DISASTER!! | ||
101 | m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); | ||
102 | m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); | ||
103 | // Something is very messed up and a crash is in our future. | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", | ||
108 | BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); | ||
109 | |||
110 | m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices); | ||
111 | if (!m_terrainShape.HasPhysicalShape) | ||
112 | { | ||
113 | // DISASTER!! | ||
114 | m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); | ||
115 | m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); | ||
116 | // Something is very messed up and a crash is in our future. | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | Vector3 pos = regionBase; | ||
121 | Quaternion rot = Quaternion.Identity; | ||
122 | |||
123 | m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); | ||
124 | if (!m_terrainBody.HasPhysicalBody) | ||
125 | { | ||
126 | // DISASTER!! | ||
127 | m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); | ||
128 | // Something is very messed up and a crash is in our future. | ||
129 | return; | ||
130 | } | ||
131 | physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); | ||
132 | |||
133 | // Set current terrain attributes | ||
134 | m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); | ||
135 | m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); | ||
136 | m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); | ||
137 | m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); | ||
138 | m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); | ||
139 | |||
140 | // Static objects are not very massive. | ||
141 | m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); | ||
142 | |||
143 | // Put the new terrain to the world of physical objects | ||
144 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody); | ||
145 | |||
146 | // Redo its bounding box now that it is in the world | ||
147 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody); | ||
148 | |||
149 | m_terrainBody.collisionType = CollisionType.Terrain; | ||
150 | m_terrainBody.ApplyCollisionMask(m_physicsScene); | ||
151 | |||
152 | if (BSParam.UseSingleSidedMeshes) | ||
153 | { | ||
154 | m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); | ||
155 | m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); | ||
156 | } | ||
157 | |||
158 | // Make it so the terrain will not move or be considered for movement. | ||
159 | m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); | ||
160 | } | ||
161 | |||
162 | public override void Dispose() | ||
163 | { | ||
164 | if (m_terrainBody.HasPhysicalBody) | ||
165 | { | ||
166 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody); | ||
167 | // Frees both the body and the shape. | ||
168 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody); | ||
169 | m_terrainBody.Clear(); | ||
170 | m_terrainShape.Clear(); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | public override float GetTerrainHeightAtXYZ(Vector3 pos) | ||
175 | { | ||
176 | // For the moment use the saved heightmap to get the terrain height. | ||
177 | // TODO: raycast downward to find the true terrain below the position. | ||
178 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
179 | |||
180 | int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X; | ||
181 | try | ||
182 | { | ||
183 | ret = m_savedHeightMap[mapIndex]; | ||
184 | } | ||
185 | catch | ||
186 | { | ||
187 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | ||
188 | m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", | ||
189 | LogHeader, TerrainBase, pos); | ||
190 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
191 | } | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | // The passed position is relative to the base of the region. | ||
196 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
197 | { | ||
198 | return m_physicsScene.SimpleWaterLevel; | ||
199 | } | ||
200 | |||
201 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | ||
202 | // Return 'true' if successfully created. | ||
203 | public static bool ConvertHeightmapToMesh( BSScene physicsScene, | ||
204 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap | ||
205 | Vector3 extentBase, // base to be added to all vertices | ||
206 | out int indicesCountO, out int[] indicesO, | ||
207 | out int verticesCountO, out float[] verticesO) | ||
208 | { | ||
209 | bool ret = false; | ||
210 | |||
211 | int indicesCount = 0; | ||
212 | int verticesCount = 0; | ||
213 | int[] indices = new int[0]; | ||
214 | float[] vertices = new float[0]; | ||
215 | |||
216 | // Simple mesh creation which assumes magnification == 1. | ||
217 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | ||
218 | |||
219 | // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop | ||
220 | // from zero to <= sizeX). The triangle indices are then generated as two triangles | ||
221 | // per heightmap point. There are sizeX by sizeY of these squares. The extra row and | ||
222 | // column of vertices are used to complete the triangles of the last row and column | ||
223 | // of the heightmap. | ||
224 | try | ||
225 | { | ||
226 | // One vertice per heightmap value plus the vertices off the side and bottom edge. | ||
227 | int totalVertices = (sizeX + 1) * (sizeY + 1); | ||
228 | vertices = new float[totalVertices * 3]; | ||
229 | int totalIndices = sizeX * sizeY * 6; | ||
230 | indices = new int[totalIndices]; | ||
231 | |||
232 | if (physicsScene != null) | ||
233 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}", | ||
234 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase); | ||
235 | float minHeight = float.MaxValue; | ||
236 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | ||
237 | for (int yy = 0; yy <= sizeY; yy++) | ||
238 | { | ||
239 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times | ||
240 | { | ||
241 | int offset = yy * sizeX + xx; | ||
242 | // Extend the height with the height from the last row or column | ||
243 | if (yy == sizeY) offset -= sizeX; | ||
244 | if (xx == sizeX) offset -= 1; | ||
245 | float height = heightMap[offset]; | ||
246 | minHeight = Math.Min(minHeight, height); | ||
247 | vertices[verticesCount + 0] = (float)xx + extentBase.X; | ||
248 | vertices[verticesCount + 1] = (float)yy + extentBase.Y; | ||
249 | vertices[verticesCount + 2] = height + extentBase.Z; | ||
250 | verticesCount += 3; | ||
251 | } | ||
252 | } | ||
253 | verticesCount = verticesCount / 3; | ||
254 | |||
255 | for (int yy = 0; yy < sizeY; yy++) | ||
256 | { | ||
257 | for (int xx = 0; xx < sizeX; xx++) | ||
258 | { | ||
259 | int offset = yy * (sizeX + 1) + xx; | ||
260 | // Each vertices is presumed to be the upper left corner of a box of two triangles | ||
261 | indices[indicesCount + 0] = offset; | ||
262 | indices[indicesCount + 1] = offset + 1; | ||
263 | indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column | ||
264 | indices[indicesCount + 3] = offset + 1; | ||
265 | indices[indicesCount + 4] = offset + sizeX + 2; | ||
266 | indices[indicesCount + 5] = offset + sizeX + 1; | ||
267 | indicesCount += 6; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | ret = true; | ||
272 | } | ||
273 | catch (Exception e) | ||
274 | { | ||
275 | if (physicsScene != null) | ||
276 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | ||
277 | LogHeader, physicsScene.RegionName, extentBase, e); | ||
278 | } | ||
279 | |||
280 | indicesCountO = indicesCount; | ||
281 | indicesO = indices; | ||
282 | verticesCountO = verticesCount; | ||
283 | verticesO = vertices; | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | private class HeightMapGetter | ||
289 | { | ||
290 | private float[] m_heightMap; | ||
291 | private int m_sizeX; | ||
292 | private int m_sizeY; | ||
293 | public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY) | ||
294 | { | ||
295 | m_heightMap = pHeightMap; | ||
296 | m_sizeX = pSizeX; | ||
297 | m_sizeY = pSizeY; | ||
298 | } | ||
299 | // The heightmap is extended as an infinite plane at the last height | ||
300 | public float GetHeight(int xx, int yy) | ||
301 | { | ||
302 | int offset = 0; | ||
303 | // Extend the height with the height from the last row or column | ||
304 | if (yy >= m_sizeY) | ||
305 | if (xx >= m_sizeX) | ||
306 | offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1); | ||
307 | else | ||
308 | offset = (m_sizeY - 1) * m_sizeX + xx; | ||
309 | else | ||
310 | if (xx >= m_sizeX) | ||
311 | offset = yy * m_sizeX + (m_sizeX - 1); | ||
312 | else | ||
313 | offset = yy * m_sizeX + xx; | ||
314 | |||
315 | return m_heightMap[offset]; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | ||
320 | // Version that handles magnification. | ||
321 | // Return 'true' if successfully created. | ||
322 | public static bool ConvertHeightmapToMesh2( BSScene physicsScene, | ||
323 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap | ||
324 | int magnification, // number of vertices per heighmap step | ||
325 | Vector3 extent, // dimensions of the output mesh | ||
326 | Vector3 extentBase, // base to be added to all vertices | ||
327 | out int indicesCountO, out int[] indicesO, | ||
328 | out int verticesCountO, out float[] verticesO) | ||
329 | { | ||
330 | bool ret = false; | ||
331 | |||
332 | int indicesCount = 0; | ||
333 | int verticesCount = 0; | ||
334 | int[] indices = new int[0]; | ||
335 | float[] vertices = new float[0]; | ||
336 | |||
337 | HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY); | ||
338 | |||
339 | // The vertices dimension of the output mesh | ||
340 | int meshX = sizeX * magnification; | ||
341 | int meshY = sizeY * magnification; | ||
342 | // The output size of one mesh step | ||
343 | float meshXStep = extent.X / meshX; | ||
344 | float meshYStep = extent.Y / meshY; | ||
345 | |||
346 | // Create an array of vertices that is meshX+1 by meshY+1 (note the loop | ||
347 | // from zero to <= meshX). The triangle indices are then generated as two triangles | ||
348 | // per heightmap point. There are meshX by meshY of these squares. The extra row and | ||
349 | // column of vertices are used to complete the triangles of the last row and column | ||
350 | // of the heightmap. | ||
351 | try | ||
352 | { | ||
353 | // Vertices for the output heightmap plus one on the side and bottom to complete triangles | ||
354 | int totalVertices = (meshX + 1) * (meshY + 1); | ||
355 | vertices = new float[totalVertices * 3]; | ||
356 | int totalIndices = meshX * meshY * 6; | ||
357 | indices = new int[totalIndices]; | ||
358 | |||
359 | if (physicsScene != null) | ||
360 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}", | ||
361 | BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY), | ||
362 | totalVertices, totalIndices, extentBase); | ||
363 | |||
364 | float minHeight = float.MaxValue; | ||
365 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | ||
366 | // Loop through the output vertices and compute the mediun height in between the input vertices | ||
367 | for (int yy = 0; yy <= meshY; yy++) | ||
368 | { | ||
369 | for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times | ||
370 | { | ||
371 | float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point | ||
372 | int stepY = (int)offsetY; | ||
373 | float fractionalY = offsetY - (float)stepY; | ||
374 | float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point | ||
375 | int stepX = (int)offsetX; | ||
376 | float fractionalX = offsetX - (float)stepX; | ||
377 | |||
378 | // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}", | ||
379 | // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY); | ||
380 | |||
381 | // get the four corners of the heightmap square the mesh point is in | ||
382 | float heightUL = hmap.GetHeight(stepX , stepY ); | ||
383 | float heightUR = hmap.GetHeight(stepX + 1, stepY ); | ||
384 | float heightLL = hmap.GetHeight(stepX , stepY + 1); | ||
385 | float heightLR = hmap.GetHeight(stepX + 1, stepY + 1); | ||
386 | |||
387 | // bilinear interplolation | ||
388 | float height = heightUL * (1 - fractionalX) * (1 - fractionalY) | ||
389 | + heightUR * fractionalX * (1 - fractionalY) | ||
390 | + heightLL * (1 - fractionalX) * fractionalY | ||
391 | + heightLR * fractionalX * fractionalY; | ||
392 | |||
393 | // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}", | ||
394 | // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height); | ||
395 | |||
396 | minHeight = Math.Min(minHeight, height); | ||
397 | |||
398 | vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X; | ||
399 | vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y; | ||
400 | vertices[verticesCount + 2] = height + extentBase.Z; | ||
401 | verticesCount += 3; | ||
402 | } | ||
403 | } | ||
404 | // The number of vertices generated | ||
405 | verticesCount /= 3; | ||
406 | |||
407 | // Loop through all the heightmap squares and create indices for the two triangles for that square | ||
408 | for (int yy = 0; yy < meshY; yy++) | ||
409 | { | ||
410 | for (int xx = 0; xx < meshX; xx++) | ||
411 | { | ||
412 | int offset = yy * (meshX + 1) + xx; | ||
413 | // Each vertices is presumed to be the upper left corner of a box of two triangles | ||
414 | indices[indicesCount + 0] = offset; | ||
415 | indices[indicesCount + 1] = offset + 1; | ||
416 | indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column | ||
417 | indices[indicesCount + 3] = offset + 1; | ||
418 | indices[indicesCount + 4] = offset + meshX + 2; | ||
419 | indices[indicesCount + 5] = offset + meshX + 1; | ||
420 | indicesCount += 6; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | ret = true; | ||
425 | } | ||
426 | catch (Exception e) | ||
427 | { | ||
428 | if (physicsScene != null) | ||
429 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | ||
430 | LogHeader, physicsScene.RegionName, extentBase, e); | ||
431 | } | ||
432 | |||
433 | indicesCountO = indicesCount; | ||
434 | indicesO = indices; | ||
435 | verticesCountO = verticesCount; | ||
436 | verticesO = vertices; | ||
437 | |||
438 | return ret; | ||
439 | } | ||
440 | } | ||
441 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs new file mode 100755 index 0000000..5932461 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs | |||
@@ -0,0 +1,277 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OMV = OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | // Classes to allow some type checking for the API | ||
35 | // These hold pointers to allocated objects in the unmanaged space. | ||
36 | // These classes are subclassed by the various physical implementations of | ||
37 | // objects. In particular, there is a version for physical instances in | ||
38 | // unmanaged memory ("unman") and one for in managed memory ("XNA"). | ||
39 | |||
40 | // Currently, the instances of these classes are a reference to a | ||
41 | // physical representation and this has no releationship to other | ||
42 | // instances. Someday, refarb the usage of these classes so each instance | ||
43 | // refers to a particular physical instance and this class controls reference | ||
44 | // counts and such. This should be done along with adding BSShapes. | ||
45 | |||
46 | public class BulletWorld | ||
47 | { | ||
48 | public BulletWorld(uint worldId, BSScene bss) | ||
49 | { | ||
50 | worldID = worldId; | ||
51 | physicsScene = bss; | ||
52 | } | ||
53 | public uint worldID; | ||
54 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
55 | public BSScene physicsScene; | ||
56 | } | ||
57 | |||
58 | // An allocated Bullet btRigidBody | ||
59 | public class BulletBody | ||
60 | { | ||
61 | public BulletBody(uint id) | ||
62 | { | ||
63 | ID = id; | ||
64 | collisionType = CollisionType.Static; | ||
65 | } | ||
66 | public uint ID; | ||
67 | public CollisionType collisionType; | ||
68 | |||
69 | public virtual void Clear() { } | ||
70 | public virtual bool HasPhysicalBody { get { return false; } } | ||
71 | |||
72 | // Apply the specificed collision mask into the physical world | ||
73 | public virtual bool ApplyCollisionMask(BSScene physicsScene) | ||
74 | { | ||
75 | // Should assert the body has been added to the physical world. | ||
76 | // (The collision masks are stored in the collision proxy cache which only exists for | ||
77 | // a collision body that is in the world.) | ||
78 | return physicsScene.PE.SetCollisionGroupMask(this, | ||
79 | BulletSimData.CollisionTypeMasks[collisionType].group, | ||
80 | BulletSimData.CollisionTypeMasks[collisionType].mask); | ||
81 | } | ||
82 | |||
83 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
84 | public virtual string AddrString | ||
85 | { | ||
86 | get { return "unknown"; } | ||
87 | } | ||
88 | |||
89 | public override string ToString() | ||
90 | { | ||
91 | StringBuilder buff = new StringBuilder(); | ||
92 | buff.Append("<id="); | ||
93 | buff.Append(ID.ToString()); | ||
94 | buff.Append(",p="); | ||
95 | buff.Append(AddrString); | ||
96 | buff.Append(",c="); | ||
97 | buff.Append(collisionType); | ||
98 | buff.Append(">"); | ||
99 | return buff.ToString(); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | public class BulletShape | ||
104 | { | ||
105 | public BulletShape() | ||
106 | { | ||
107 | shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
108 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
109 | isNativeShape = false; | ||
110 | } | ||
111 | public BSPhysicsShapeType shapeType; | ||
112 | public System.UInt64 shapeKey; | ||
113 | public bool isNativeShape; | ||
114 | |||
115 | public virtual void Clear() { } | ||
116 | public virtual bool HasPhysicalShape { get { return false; } } | ||
117 | |||
118 | // Make another reference to this physical object. | ||
119 | public virtual BulletShape Clone() { return new BulletShape(); } | ||
120 | |||
121 | // Return 'true' if this and other refer to the same physical object | ||
122 | public virtual bool ReferenceSame(BulletShape xx) { return false; } | ||
123 | |||
124 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
125 | public virtual string AddrString | ||
126 | { | ||
127 | get { return "unknown"; } | ||
128 | } | ||
129 | |||
130 | public override string ToString() | ||
131 | { | ||
132 | StringBuilder buff = new StringBuilder(); | ||
133 | buff.Append("<p="); | ||
134 | buff.Append(AddrString); | ||
135 | buff.Append(",s="); | ||
136 | buff.Append(shapeType.ToString()); | ||
137 | buff.Append(",k="); | ||
138 | buff.Append(shapeKey.ToString("X")); | ||
139 | buff.Append(",n="); | ||
140 | buff.Append(isNativeShape.ToString()); | ||
141 | buff.Append(">"); | ||
142 | return buff.ToString(); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | // An allocated Bullet btConstraint | ||
147 | public class BulletConstraint | ||
148 | { | ||
149 | public BulletConstraint() | ||
150 | { | ||
151 | } | ||
152 | public virtual void Clear() { } | ||
153 | public virtual bool HasPhysicalConstraint { get { return false; } } | ||
154 | |||
155 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
156 | public virtual string AddrString | ||
157 | { | ||
158 | get { return "unknown"; } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | // An allocated HeightMapThing which holds various heightmap info. | ||
163 | // Made a class rather than a struct so there would be only one | ||
164 | // instance of this and C# will pass around pointers rather | ||
165 | // than making copies. | ||
166 | public class BulletHMapInfo | ||
167 | { | ||
168 | public BulletHMapInfo(uint id, float[] hm, float pSizeX, float pSizeY) { | ||
169 | ID = id; | ||
170 | heightMap = hm; | ||
171 | terrainRegionBase = OMV.Vector3.Zero; | ||
172 | minCoords = new OMV.Vector3(100f, 100f, 25f); | ||
173 | maxCoords = new OMV.Vector3(101f, 101f, 26f); | ||
174 | minZ = maxZ = 0f; | ||
175 | sizeX = pSizeX; | ||
176 | sizeY = pSizeY; | ||
177 | } | ||
178 | public uint ID; | ||
179 | public float[] heightMap; | ||
180 | public OMV.Vector3 terrainRegionBase; | ||
181 | public OMV.Vector3 minCoords; | ||
182 | public OMV.Vector3 maxCoords; | ||
183 | public float sizeX, sizeY; | ||
184 | public float minZ, maxZ; | ||
185 | public BulletShape terrainShape; | ||
186 | public BulletBody terrainBody; | ||
187 | } | ||
188 | |||
189 | // The general class of collsion object. | ||
190 | public enum CollisionType | ||
191 | { | ||
192 | Avatar, | ||
193 | PhantomToOthersAvatar, // An avatar that it phantom to other avatars but not to anything else | ||
194 | Groundplane, | ||
195 | Terrain, | ||
196 | Static, | ||
197 | Dynamic, | ||
198 | VolumeDetect, | ||
199 | // Linkset, // A linkset should be either Static or Dynamic | ||
200 | LinksetChild, | ||
201 | Unknown | ||
202 | }; | ||
203 | |||
204 | // Hold specification of group and mask collision flags for a CollisionType | ||
205 | public struct CollisionTypeFilterGroup | ||
206 | { | ||
207 | public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) | ||
208 | { | ||
209 | type = t; | ||
210 | group = g; | ||
211 | mask = m; | ||
212 | } | ||
213 | public CollisionType type; | ||
214 | public uint group; | ||
215 | public uint mask; | ||
216 | }; | ||
217 | |||
218 | public static class BulletSimData | ||
219 | { | ||
220 | |||
221 | // Map of collisionTypes to flags for collision groups and masks. | ||
222 | // An object's 'group' is the collison groups this object belongs to | ||
223 | // An object's 'filter' is the groups another object has to belong to in order to collide with me | ||
224 | // A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0) | ||
225 | // | ||
226 | // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code | ||
227 | // but, instead, use references to this dictionary. Finding and debugging | ||
228 | // collision flag problems will be made easier. | ||
229 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | ||
230 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() | ||
231 | { | ||
232 | { CollisionType.Avatar, | ||
233 | new CollisionTypeFilterGroup(CollisionType.Avatar, | ||
234 | (uint)CollisionFilterGroups.BCharacterGroup, | ||
235 | (uint)(CollisionFilterGroups.BAllGroup)) | ||
236 | }, | ||
237 | { CollisionType.PhantomToOthersAvatar, | ||
238 | new CollisionTypeFilterGroup(CollisionType.PhantomToOthersAvatar, | ||
239 | (uint)CollisionFilterGroups.BCharacterGroup, | ||
240 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup)) | ||
241 | }, | ||
242 | { CollisionType.Groundplane, | ||
243 | new CollisionTypeFilterGroup(CollisionType.Groundplane, | ||
244 | (uint)CollisionFilterGroups.BGroundPlaneGroup, | ||
245 | // (uint)CollisionFilterGroups.BAllGroup) | ||
246 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
247 | }, | ||
248 | { CollisionType.Terrain, | ||
249 | new CollisionTypeFilterGroup(CollisionType.Terrain, | ||
250 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
251 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | ||
252 | }, | ||
253 | { CollisionType.Static, | ||
254 | new CollisionTypeFilterGroup(CollisionType.Static, | ||
255 | (uint)CollisionFilterGroups.BStaticGroup, | ||
256 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
257 | }, | ||
258 | { CollisionType.Dynamic, | ||
259 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | ||
260 | (uint)CollisionFilterGroups.BSolidGroup, | ||
261 | (uint)(CollisionFilterGroups.BAllGroup)) | ||
262 | }, | ||
263 | { CollisionType.VolumeDetect, | ||
264 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | ||
265 | (uint)CollisionFilterGroups.BSensorTrigger, | ||
266 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | ||
267 | }, | ||
268 | { CollisionType.LinksetChild, | ||
269 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | ||
270 | (uint)CollisionFilterGroups.BLinksetChildGroup, | ||
271 | (uint)(CollisionFilterGroups.BNoneGroup)) | ||
272 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
273 | }, | ||
274 | }; | ||
275 | |||
276 | } | ||
277 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt new file mode 100755 index 0000000..0453376 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt | |||
@@ -0,0 +1,379 @@ | |||
1 | CURRENT PROBLEMS TO FIX AND/OR LOOK AT | ||
2 | ================================================= | ||
3 | Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass. | ||
4 | Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive? | ||
5 | Negative buoyancy computed correctly | ||
6 | Center-of-gravity | ||
7 | Computation of mesh mass. How done? How should it be done? | ||
8 | Enable vehicle border crossings (at least as poorly as ODE) | ||
9 | Terrain skirts | ||
10 | Avatar created in previous region and not new region when crossing border | ||
11 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | ||
12 | User settable terrain mesh | ||
13 | Allow specifying as convex or concave and use different getHeight functions depending | ||
14 | Boats, when turning nose down into the water | ||
15 | Acts like rotation around Z is also effecting rotation around X and Y | ||
16 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. | ||
17 | Not sure if it is because standing on it. Done with large prim linksets. | ||
18 | Linkset child rotations. | ||
19 | Nebadon spiral tube has middle sections which are rotated wrong. | ||
20 | Select linked spiral tube. Delink and note where the middle section ends up. | ||
21 | Teravus llMoveToTarget script debug | ||
22 | Mixing of hover, buoyancy/gravity, moveToTarget, into one force | ||
23 | Setting hover height to zero disables hover even if hover flags are on (from SL wiki) | ||
24 | limitMotorUp calibration (more down?) | ||
25 | llRotLookAt | ||
26 | llLookAt | ||
27 | Convert to avatar mesh capsule. Include rotation of capsule. | ||
28 | Vehicle script tuning/debugging | ||
29 | Avanti speed script | ||
30 | Weapon shooter script | ||
31 | Move material definitions (friction, ...) into simulator. | ||
32 | osGetPhysicsEngineVerion() and create a version code for the C++ DLL | ||
33 | One sided meshes? Should terrain be built into a closed shape? | ||
34 | When meshes get partially wedged into the terrain, they cannot push themselves out. | ||
35 | It is possible that Bullet processes collisions whether entering or leaving a mesh. | ||
36 | Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869 | ||
37 | Small physical objects do not interact correctly | ||
38 | Create chain of .5x.5x.1 torui and make all but top physical so to hang. | ||
39 | The chain will fall apart and pairs will dance around on ground | ||
40 | Chains of 1x1x.2 will stay connected but will dance. | ||
41 | Chains above 2x2x.4 are more stable and get stablier as torui get larger. | ||
42 | |||
43 | VEHICLES TODO LIST: | ||
44 | ================================================= | ||
45 | LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers. | ||
46 | What are the limits in SL? | ||
47 | Same for other velocity settings. | ||
48 | UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: | ||
49 | https://github.com/UbitUmarov/Ubit-opensim | ||
50 | Some vehicles should not be able to turn if no speed or off ground. | ||
51 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | ||
52 | Neb car jiggling left and right | ||
53 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | ||
54 | This has been reduced but not eliminated. | ||
55 | Implement referenceFrame for all the motion routines. | ||
56 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | ||
57 | llGetVel() should return the root's velocity if requested in a child prim. | ||
58 | Implement function efficiency for lineaar and angular motion. | ||
59 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | ||
60 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). | ||
61 | A kludge that isn't fixing the real problem of Bullet adding extra motion. | ||
62 | Incorporate inter-relationship of angular corrections. For instance, angularDeflection | ||
63 | and angularMotorUp will compute same X or Y correction. When added together | ||
64 | creates over-correction and over-shoot and wabbling. | ||
65 | Vehicle attributes are not restored when a vehicle is rezzed on region creation | ||
66 | Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. | ||
67 | What to do if vehicle and prim buoyancy differ? | ||
68 | |||
69 | GENERAL TODO LIST: | ||
70 | ================================================= | ||
71 | Resitution of a prim works on another prim but not on terrain. | ||
72 | The dropped prim doesn't bounce properly on the terrain. | ||
73 | Add a sanity check for PIDTarget location. | ||
74 | Level-of-detail for mesh creation. Prims with circular interiors require lod of 32. | ||
75 | Is much saved with lower LODs? At the moment, all set to 32. | ||
76 | Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't. | ||
77 | If arrow show at prim, collision reported about 1/3 of time. If collision reported, | ||
78 | both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times. | ||
79 | Shooting 5m sphere "arrows" at 60m/s. | ||
80 | llMoveToTarget objects are not effected by gravity until target is removed. | ||
81 | Compute CCD parameters based on body size | ||
82 | Can solver iterations be changed per body/shape? Can be for constraints but what | ||
83 | about regular vehicles? | ||
84 | Implement llSetPhysicalMaterial. | ||
85 | extend it with Center-of-mass, rolling friction, density | ||
86 | Implement llSetForceAndTorque. | ||
87 | Change BSPrim.moveToTarget to used forces rather than changing position | ||
88 | Changing position allows one to move through walls | ||
89 | Implement an avatar mesh shape. The Bullet capsule is way too limited. | ||
90 | Consider just hand creating a vertex/index array in a new BSShapeAvatar. | ||
91 | Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain. | ||
92 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. | ||
93 | Duplicating a physical prim causes old prim to jump away | ||
94 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. | ||
95 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. | ||
96 | Gun sending shooter flying. | ||
97 | Collision margin (gap between physical objects lying on each other) | ||
98 | Boundry checking (crashes related to crossing boundry) | ||
99 | Add check for border edge position for avatars and objects. | ||
100 | Verify the events are created for border crossings. | ||
101 | Implement ShapeCollection.Dispose() | ||
102 | Implement water as a plain or mesh so raycasting and collisions can happen with same. | ||
103 | Add collision penetration return | ||
104 | Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance() | ||
105 | Linkset.Position and Linkset.Orientation requre rewrite to properly return | ||
106 | child position. LinksetConstraint acts like it's at taint time!! | ||
107 | Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) | ||
108 | Should the different PID factors have non-equal contributions for different | ||
109 | values of Efficiency? | ||
110 | Selecting and deselecting physical objects causes CPU processing time to jump | ||
111 | http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1 | ||
112 | put thousand physical objects, select and deselect same. CPU time will be large. | ||
113 | Re-implement buoyancy as a separate force on the object rather than diddling gravity. | ||
114 | Register a pre-step event to add the force. | ||
115 | More efficient memory usage when passing hull information from BSPrim to BulletSim | ||
116 | Physical and phantom will drop through the terrain | ||
117 | |||
118 | |||
119 | LINKSETS | ||
120 | ====================================================== | ||
121 | Child prims do not report collisions | ||
122 | Allow children of a linkset to be phantom: | ||
123 | http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html | ||
124 | Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast. | ||
125 | Editing a child of a linkset causes the child to go phantom | ||
126 | Move a child prim once when it is physical and can never move it again without it going phantom | ||
127 | Offset the center of the linkset to be the geometric center of all the prims | ||
128 | Not quite the same as the center-of-gravity | ||
129 | Linksets should allow collisions to individual children | ||
130 | Add LocalID to children shapes in LinksetCompound and create events for individuals | ||
131 | LinksetCompound: when one of the children changes orientation (like tires | ||
132 | turning on a vehicle, the whole compound object is rebuilt. Optimize this | ||
133 | so orientation/position of individual children can change without a rebuild. | ||
134 | Verify/think through scripts in children of linksets. What do they reference | ||
135 | and return when getting position, velocity, ... | ||
136 | Confirm constraint linksets still work after making all the changes for compound linksets. | ||
137 | Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding | ||
138 | Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. | ||
139 | For compound linksets, add ability to remove or reposition individual child shapes. | ||
140 | Speed up creation of large physical linksets | ||
141 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. | ||
142 | REALLY bad for very large physical linksets (freezes the sim for many seconds). | ||
143 | Eliminate collisions between objects in a linkset. (LinksetConstraint) | ||
144 | Have UserPointer point to struct with localID and linksetID? | ||
145 | Objects in original linkset still collide with each other? | ||
146 | |||
147 | MORE | ||
148 | ====================================================== | ||
149 | Compute avatar size and scale correctly. Now it is a bit off from the capsule size. | ||
150 | Create tests for different interface components | ||
151 | Have test objects/scripts measure themselves and turn color if correct/bad | ||
152 | Test functions in SL and calibrate correctness there | ||
153 | Create auto rezzer and tracker to run through the tests | ||
154 | Do we need to do convex hulls all the time? Can complex meshes be left meshes? | ||
155 | There is some problem with meshes and collisions | ||
156 | Hulls are not as detailed as meshes. Hulled vehicles insides are different shape. | ||
157 | Debounce avatar contact so legs don't keep folding up when standing. | ||
158 | Add border extensions to terrain to help region crossings and objects leaving region. | ||
159 | Use a different capsule shape for avatar when sitting | ||
160 | LL uses a pyrimidal shape scaled by the avatar's bounding box | ||
161 | http://wiki.secondlife.com/wiki/File:Avmeshforms.png | ||
162 | Performance test with lots of avatars. Can BulletSim support a thousand? | ||
163 | Optimize collisions in C++: only send up to the object subscribed to collisions. | ||
164 | Use collision subscription and remove the collsion(A,B) and collision(B,A) | ||
165 | Check whether SimMotionState needs large if statement (see TODO). | ||
166 | Implement 'top colliders' info. | ||
167 | Avatar jump | ||
168 | Performance measurement and changes to make quicker. | ||
169 | Implement detailed physics stats (GetStats()). | ||
170 | Measure performance improvement from hulls | ||
171 | Test not using ghost objects for volume detect implementation. | ||
172 | Performance of closures and delegates for taint processing | ||
173 | Are there faster ways? | ||
174 | Is any slowdown introduced by the existing implementation significant? | ||
175 | Is there are more efficient method of implementing pre and post step actions? | ||
176 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C | ||
177 | Physics Arena central pyramid: why is one side permiable? | ||
178 | In SL, perfect spheres don't seem to have rolling friction. Add special case. | ||
179 | Enforce physical parameter min/max: | ||
180 | Gravity: [-1, 28] | ||
181 | Friction: [0, 255] | ||
182 | Density: [1, 22587] | ||
183 | Restitution [0, 1] | ||
184 | http://wiki.secondlife.com/wiki/Physics_Material_Settings_test | ||
185 | Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html | ||
186 | Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html | ||
187 | |||
188 | INTERNAL IMPROVEMENT/CLEANUP | ||
189 | ================================================= | ||
190 | Create the physical wrapper classes (BulletBody, BulletShape) by methods on | ||
191 | BSAPITemplate and make their actual implementation Bullet engine specific. | ||
192 | For the short term, just call the existing functions in ShapeCollection. | ||
193 | Consider moving prim/character body and shape destruction in destroy() | ||
194 | to postTimeTime rather than protecting all the potential sets that | ||
195 | might have been queued up. | ||
196 | Remove unused fields from ShapeData (not used in API2) | ||
197 | Remove unused fields from pinned memory shared parameter block | ||
198 | Create parameter variables in BSScene to replace same. | ||
199 | Breakout code for mesh/hull/compound/native into separate BSShape* classes | ||
200 | Standardize access to building and reference code. | ||
201 | The skeleton classes are in the sources but are not complete or linked in. | ||
202 | Make BSBody and BSShape real classes to centralize creation/changin/destruction | ||
203 | Convert state and parameter calls from BulletSimAPI direct calls to | ||
204 | calls on BSBody and BSShape | ||
205 | Generalize Dynamics and PID with standardized motors. | ||
206 | Generalize Linkset and vehicles into PropertyManagers | ||
207 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies | ||
208 | Potentially add events for shape destruction, etc. | ||
209 | Better mechanism for resetting linkset set and vehicle parameters when body rebuilt. | ||
210 | BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc. | ||
211 | Implement linkset by setting position of children when root updated. (LinksetManual) | ||
212 | Linkset implementation using manual prim movement. | ||
213 | LinkablePrim class? Would that simplify/centralize the linkset logic? | ||
214 | BSScene.UpdateParameterSet() is broken. How to set params on objects? | ||
215 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will | ||
216 | bob at the water level. BSPrim.PositionSanityCheck() | ||
217 | Should taints check for existance or activeness of target? | ||
218 | When destroying linksets/etc, taints can be generated for objects that are | ||
219 | actually gone when the taint happens. Crashes don't happen because the taint closure | ||
220 | keeps the object from being freed, but that is just an accident. | ||
221 | Possibly have an 'active' flag that is checked by the taint processor? | ||
222 | Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) | ||
223 | Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? | ||
224 | There are TOO MANY interfaces from BulletSim core to Bullet itself | ||
225 | Think of something to eliminate one or more of the layers | ||
226 | |||
227 | THREADING | ||
228 | ================================================= | ||
229 | Do taint action immediately if not actually executing Bullet. | ||
230 | Add lock around Bullet execution and just do taint actions if simulation is not happening. | ||
231 | |||
232 | DONE DONE DONE DONE | ||
233 | ================================================= | ||
234 | Cleanup code in BSDynamics by using motors. (Resolution: started) | ||
235 | Consider implementing terrain with a mesh rather than heightmap. (Resolution: done) | ||
236 | Would have better and adjustable resolution. | ||
237 | Build terrain mesh so heighmap is height of the center of the square meter. | ||
238 | Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional. | ||
239 | Terrain as mesh. (Resolution: done) | ||
240 | How are static linksets seen by the physics engine? | ||
241 | Resolution: they are not linked in physics. When moved, all the children are repositioned. | ||
242 | Convert BSCharacter to use all API2 (Resolution: done) | ||
243 | Avatar pushing difficult (too heavy?) | ||
244 | Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done) | ||
245 | Remove old code in DLL (all non-API2 stuff). (Resolution: done) | ||
246 | Measurements of mega-physical prim performance (with graph) (Resolution: done, email) | ||
247 | Debug Bullet internal stats output (why is timing all wrong?) | ||
248 | Resolution: Bullet stats logging only works with a single instance of Bullet (one region). | ||
249 | Implement meshes or just verify that they work. (Resolution: they do!) | ||
250 | Do prim hash codes work for sculpties and meshes? (Resolution: yes) | ||
251 | Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) | ||
252 | Compound shapes will need the LocalID in the shapes and collision | ||
253 | processing to get it from there. | ||
254 | Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) | ||
255 | Package Bullet source mods for Bullet internal stats output | ||
256 | (Resolution: move code into WorldData.h rather than relying on patches) | ||
257 | Single prim vehicles don't seem to properly vehiclize. | ||
258 | (Resolution: mass was not getting set properly for single prim linksets) | ||
259 | Add material type linkage and input all the material property definitions. | ||
260 | Skeleton classes and table are in the sources but are not filled or used. | ||
261 | (Resolution: | ||
262 | Neb vehicle taking > 25ms of physics time!! | ||
263 | (Resolution: compound linksets were being rebuild WAY too often) | ||
264 | Avatar height off after unsitting (floats off ground) | ||
265 | Editting appearance then moving restores. | ||
266 | Must not be initializing height when recreating capsule after unsit. | ||
267 | (Resolution: confusion of scale vs size for native objects removed) | ||
268 | Light cycle falling over when driving (Resolution: implemented angularMotorUp) | ||
269 | Should vehicle angular/linear movement friction happen after all the components | ||
270 | or does it only apply to the basic movement? | ||
271 | (Resolution: friction added before returning newly computed motor value. | ||
272 | What is expected by some vehicles (turning up friction to moderate speed)) | ||
273 | Tune terrain/object friction to be closer to SL. | ||
274 | (Resolution: added material type with friction and resolution) | ||
275 | Smooth avatar movement with motor (DONE) | ||
276 | Should motor update be all at taint-time? (Yes, DONE) | ||
277 | Fix avatar slowly sliding when standing (zero motion when stopped) (DONE) | ||
278 | (Resolution: added BSVMotor for avatar starting and stopping) | ||
279 | llApplyImpulse() | ||
280 | Compare mass/movement in OS and SL. Calibrate actions. (DONE) | ||
281 | (Resolution: tested on SL and OS. AddForce scales the force for timestep) | ||
282 | llSetBuoyancy() (DONE) | ||
283 | (Resolution: Bullet resets object gravity when added to world. Moved set gravity) | ||
284 | Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) | ||
285 | (Resolution: set default density to 3.5 (from 60) which is closer to SL) | ||
286 | Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE) | ||
287 | (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA | ||
288 | Meshes rendering as bounding boxes (DONE) | ||
289 | (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box) | ||
290 | llMoveToTarget (Resolution: added simple motor to update the position.) | ||
291 | Angular motor direction is global coordinates rather than local coordinates (DONE) | ||
292 | Add vehicle collisions so IsColliding is properly reported. (DONE) | ||
293 | Needed for banking, limitMotorUp, movementLimiting, ... | ||
294 | (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it) | ||
295 | VehicleAddForce is not scaled by the simulation step but it is only | ||
296 | applied for one step. Should it be scaled? (DONE) | ||
297 | (Resolution: use force for timed things, Impulse for immediate, non-timed things) | ||
298 | Complete implemention of preStepActions (DONE) | ||
299 | Replace vehicle step call with prestep event. | ||
300 | Is there a need for postStepActions? postStepTaints? | ||
301 | Disable activity of passive linkset children. (DONE) | ||
302 | Since the linkset is a compound object, the old prims are left lying | ||
303 | around and need to be phantomized so they don't collide, ... | ||
304 | Remove HeightmapInfo from terrain specification (DONE) | ||
305 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
306 | Surfboard go wonky when turning (DONE) | ||
307 | Angular motor direction is global coordinates rather than local coordinates? | ||
308 | (Resolution: made angular motor direction correct coordinate system) | ||
309 | Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE) | ||
310 | Msg Kayaker on OSGrid when working | ||
311 | (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the | ||
312 | same in SL as in OS/BulletSim) | ||
313 | Boats float low in the water (DONE) | ||
314 | Boats floating at proper level (DONE) | ||
315 | When is force introduced by SetForce removed? The prestep action could go forever. (DONE) | ||
316 | (Resolution: setForce registers a prestep action which keeps applying the force) | ||
317 | Child movement in linkset (don't rebuild linkset) (DONE 20130122)) | ||
318 | Avatar standing on a moving object should start to move with the object. (DONE 20130125) | ||
319 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | ||
320 | Verify that angular motion specified around Z moves in the vehicle coordinates. | ||
321 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. | ||
322 | Nebadon vehicles turning funny in arena (DONE) | ||
323 | Lock axis (DONE 20130401) | ||
324 | Terrain detail: double terrain mesh detail (DONE) | ||
325 | Use the HACD convex hull routine in Bullet rather than the C# version. | ||
326 | Speed up hullifying large meshes. (DONE) | ||
327 | Vehicle ride, get up, ride again. Second time vehicle does not act correctly. | ||
328 | Have to rez new vehicle and delete the old to fix situation. | ||
329 | (DONE 20130520: normalize rotations) | ||
330 | Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd | ||
331 | position state where it will not settle onto ground properly, etc | ||
332 | (DONE 20130520: normalize rotations) | ||
333 | Two of Nebadon vehicles in a sim max the CPU. This is new. | ||
334 | (DONE 20130520: two problems: if asset failed to mesh, constantly refetched | ||
335 | asset; vehicle was sending too many messages to all linkset members) | ||
336 | Add material densities to the material types. (WILL NOT BE DONE: not how it is done) | ||
337 | Avatars walking up stairs (DONE) | ||
338 | Avatar movement | ||
339 | flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) | ||
340 | walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) | ||
341 | avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) | ||
342 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
343 | Need to force a position update for the root prim after compound shape destruction | ||
344 | (DONE) | ||
345 | Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. | ||
346 | Regular triangle meshes don't do physical collisions. | ||
347 | (DONE: discovered GImpact is VERY CPU intensive) | ||
348 | Script changing rotation of child prim while vehicle moving (eg turning wheel) causes | ||
349 | the wheel to appear to jump back. Looks like sending position from previous update. | ||
350 | (DONE: redo of compound linksets fixed problem) | ||
351 | Refarb compound linkset creation to create a pseudo-root for center-of-mass | ||
352 | Let children change their shape to physical indendently and just add shapes to compound | ||
353 | (DONE: redo of compound linkset fixed problem) | ||
354 | Vehicle angular vertical attraction (DONE: vegaslon code) | ||
355 | vehicle angular banking (DONE: vegaslon code) | ||
356 | Vehicle angular deflection (DONE: vegaslon code) | ||
357 | Preferred orientation angular correction fix | ||
358 | Vehicles (Move smoothly) | ||
359 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
360 | (WILL NOT BE DONE: gravity does the job well enough) | ||
361 | BSPrim.Force should set a continious force on the prim. The force should be | ||
362 | applied each tick. Some limits? | ||
363 | (DONE: added physical actors. Implemented SetForce, SetTorque, ...) | ||
364 | Implement LSL physics controls. Like STATUS_ROTATE_X. (DONE) | ||
365 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | ||
366 | Avatar rotation (check out changes to ScenePresence for physical rotation) (DONE) | ||
367 | Avatar running (what does phys engine need to do?) (DONE: multiplies run factor by walking force) | ||
368 | setForce should set a constant force. Different than AddImpulse. (DONE) | ||
369 | Add PID motor for avatar movement (slow to stop, ...) (WNBD: current works ok) | ||
370 | Avatar movement motor check for zero or small movement. Somehow suppress small movements | ||
371 | when avatar has stopped and is just standing. Simple test for near zero has | ||
372 | the problem of preventing starting up (increase from zero) especially when falling. | ||
373 | (DONE: avatar movement actor knows if standing on stationary object and zeros motion) | ||
374 | Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to | ||
375 | BSScene.TaintedObject() could immediately execute the callback if already in taint time. | ||
376 | (DONE) | ||
377 | |||
378 | |||
379 | |||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4f90eee --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs | |||
@@ -0,0 +1,33 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using System.Runtime.InteropServices; | ||
4 | |||
5 | // General Information about an assembly is controlled through the following | ||
6 | // set of attributes. Change these attribute values to modify the information | ||
7 | // associated with an assembly. | ||
8 | [assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")] | ||
9 | [assembly: AssemblyDescription("")] | ||
10 | [assembly: AssemblyConfiguration("")] | ||
11 | [assembly: AssemblyCompany("http://opensimulator.org")] | ||
12 | [assembly: AssemblyProduct("OpenSim")] | ||
13 | [assembly: AssemblyCopyright("OpenSimulator developers")] | ||
14 | [assembly: AssemblyTrademark("")] | ||
15 | [assembly: AssemblyCulture("")] | ||
16 | |||
17 | // Setting ComVisible to false makes the types in this assembly not visible | ||
18 | // to COM components. If you need to access a type in this assembly from | ||
19 | // COM, set the ComVisible attribute to true on that type. | ||
20 | [assembly: ComVisible(false)] | ||
21 | |||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | ||
23 | [assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")] | ||
24 | |||
25 | // Version information for an assembly consists of the following four values: | ||
26 | // | ||
27 | // Major Version | ||
28 | // Minor Version | ||
29 | // Build Number | ||
30 | // Revision | ||
31 | // | ||
32 | [assembly: AssemblyVersion("0.8.2.*")] | ||
33 | |||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs new file mode 100755 index 0000000..48e74eb --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs | |||
@@ -0,0 +1,156 @@ | |||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using NUnit.Framework; | ||
34 | using log4net; | ||
35 | |||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Physics.BulletSPlugin; | ||
38 | using OpenSim.Region.Physics.Manager; | ||
39 | using OpenSim.Tests.Common; | ||
40 | |||
41 | using OpenMetaverse; | ||
42 | |||
43 | namespace OpenSim.Region.Physics.BulletSPlugin.Tests | ||
44 | { | ||
45 | [TestFixture] | ||
46 | public class BasicVehicles : OpenSimTestCase | ||
47 | { | ||
48 | // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 | ||
49 | // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 | ||
50 | |||
51 | BSScene PhysicsScene { get; set; } | ||
52 | BSPrim TestVehicle { get; set; } | ||
53 | Vector3 TestVehicleInitPosition { get; set; } | ||
54 | float simulationTimeStep = 0.089f; | ||
55 | |||
56 | [TestFixtureSetUp] | ||
57 | public void Init() | ||
58 | { | ||
59 | Dictionary<string, string> engineParams = new Dictionary<string, string>(); | ||
60 | engineParams.Add("VehicleEnableAngularVerticalAttraction", "true"); | ||
61 | engineParams.Add("VehicleAngularVerticalAttractionAlgorithm", "1"); | ||
62 | PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); | ||
63 | |||
64 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere(); | ||
65 | Vector3 pos = new Vector3(100.0f, 100.0f, 0f); | ||
66 | pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f; | ||
67 | TestVehicleInitPosition = pos; | ||
68 | Vector3 size = new Vector3(1f, 1f, 1f); | ||
69 | pbs.Scale = size; | ||
70 | Quaternion rot = Quaternion.Identity; | ||
71 | bool isPhys = false; | ||
72 | uint localID = 123; | ||
73 | |||
74 | PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID); | ||
75 | TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID]; | ||
76 | // The actual prim shape creation happens at taint time | ||
77 | PhysicsScene.ProcessTaints(); | ||
78 | |||
79 | } | ||
80 | |||
81 | [TestFixtureTearDown] | ||
82 | public void TearDown() | ||
83 | { | ||
84 | if (PhysicsScene != null) | ||
85 | { | ||
86 | // The Dispose() will also free any physical objects in the scene | ||
87 | PhysicsScene.Dispose(); | ||
88 | PhysicsScene = null; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)] | ||
93 | [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)] | ||
94 | [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)] | ||
95 | [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)] | ||
96 | // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */] | ||
97 | // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */] | ||
98 | // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */] | ||
99 | // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */] | ||
100 | // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */] | ||
101 | // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */] | ||
102 | // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */] | ||
103 | // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */] | ||
104 | public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw) | ||
105 | { | ||
106 | // Enough simulation steps to cover the timescale the operation should take | ||
107 | int simSteps = (int)(timeScale / simulationTimeStep) + 1; | ||
108 | |||
109 | // Tip the vehicle | ||
110 | Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw); | ||
111 | TestVehicle.Orientation = initOrientation; | ||
112 | |||
113 | TestVehicle.Position = TestVehicleInitPosition; | ||
114 | |||
115 | // The vehicle controller is not enabled directly (by setting a vehicle type). | ||
116 | // Instead the appropriate values are set and calls are made just the parts of the | ||
117 | // controller we want to exercise. Stepping the physics engine then applies | ||
118 | // the actions of that one feature. | ||
119 | BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */); | ||
120 | if (vehicleActor != null) | ||
121 | { | ||
122 | vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); | ||
123 | vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); | ||
124 | // vehicleActor.enableAngularVerticalAttraction = true; | ||
125 | |||
126 | TestVehicle.IsPhysical = true; | ||
127 | PhysicsScene.ProcessTaints(); | ||
128 | |||
129 | // Step the simulator a bunch of times and vertical attraction should orient the vehicle up | ||
130 | for (int ii = 0; ii < simSteps; ii++) | ||
131 | { | ||
132 | vehicleActor.ForgetKnownVehicleProperties(); | ||
133 | vehicleActor.ComputeAngularVerticalAttraction(); | ||
134 | vehicleActor.PushKnownChanged(); | ||
135 | |||
136 | PhysicsScene.Simulate(simulationTimeStep); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | TestVehicle.IsPhysical = false; | ||
141 | PhysicsScene.ProcessTaints(); | ||
142 | |||
143 | // After these steps, the vehicle should be upright | ||
144 | /* | ||
145 | float finalRoll, finalPitch, finalYaw; | ||
146 | TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw); | ||
147 | Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f)); | ||
148 | Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f)); | ||
149 | Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f)); | ||
150 | */ | ||
151 | |||
152 | Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation; | ||
153 | Assert.That(upPointer.Z, Is.GreaterThan(0.99f)); | ||
154 | } | ||
155 | } | ||
156 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs new file mode 100755 index 0000000..35cbc1d --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs | |||
@@ -0,0 +1,56 @@ | |||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using NUnit.Framework; | ||
34 | using log4net; | ||
35 | |||
36 | using OpenSim.Tests.Common; | ||
37 | |||
38 | namespace OpenSim.Region.Physics.BulletSPlugin.Tests | ||
39 | { | ||
40 | [TestFixture] | ||
41 | public class BulletSimTests : OpenSimTestCase | ||
42 | { | ||
43 | // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 | ||
44 | // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 | ||
45 | |||
46 | [TestFixtureSetUp] | ||
47 | public void Init() | ||
48 | { | ||
49 | } | ||
50 | |||
51 | [TestFixtureTearDown] | ||
52 | public void TearDown() | ||
53 | { | ||
54 | } | ||
55 | } | ||
56 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs new file mode 100755 index 0000000..775bca2 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs | |||
@@ -0,0 +1,100 @@ | |||
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.IO; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Text; | ||
32 | |||
33 | using Nini.Config; | ||
34 | |||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Region.Physics.Manager; | ||
37 | using OpenSim.Region.Physics.Meshing; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSPlugin.Tests | ||
42 | { | ||
43 | // Utility functions for building up and tearing down the sample physics environments | ||
44 | public static class BulletSimTestsUtil | ||
45 | { | ||
46 | // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA" | ||
47 | // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults) | ||
48 | // May be 'null' if there are no overrides. | ||
49 | public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides) | ||
50 | { | ||
51 | IConfigSource openSimINI = new IniConfigSource(); | ||
52 | IConfig startupConfig = openSimINI.AddConfig("Startup"); | ||
53 | startupConfig.Set("physics", "BulletSim"); | ||
54 | startupConfig.Set("meshing", "Meshmerizer"); | ||
55 | startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps | ||
56 | |||
57 | IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim"); | ||
58 | // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged". | ||
59 | // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged"); | ||
60 | // bulletSimConfig.Set("BulletEngine", "BulletXNA"); | ||
61 | bulletSimConfig.Set("MeshSculptedPrim", "false"); | ||
62 | bulletSimConfig.Set("ForceSimplePrimMeshing", "true"); | ||
63 | if (paramOverrides != null) | ||
64 | { | ||
65 | foreach (KeyValuePair<string, string> kvp in paramOverrides) | ||
66 | { | ||
67 | bulletSimConfig.Set(kvp.Key, kvp.Value); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | // If a special directory exists, put detailed logging therein. | ||
72 | // This allows local testing/debugging without having to worry that the build engine will output logs. | ||
73 | if (Directory.Exists("physlogs")) | ||
74 | { | ||
75 | bulletSimConfig.Set("PhysicsLoggingDir","./physlogs"); | ||
76 | bulletSimConfig.Set("PhysicsLoggingEnabled","True"); | ||
77 | bulletSimConfig.Set("PhysicsLoggingDoFlush","True"); | ||
78 | bulletSimConfig.Set("VehicleLoggingEnabled","True"); | ||
79 | } | ||
80 | |||
81 | PhysicsPluginManager physicsPluginManager; | ||
82 | physicsPluginManager = new PhysicsPluginManager(); | ||
83 | physicsPluginManager.LoadPluginsFromAssemblies("Physics"); | ||
84 | |||
85 | Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
86 | |||
87 | PhysicsScene pScene = physicsPluginManager.GetPhysicsScene( | ||
88 | "BulletSim", "Meshmerizer", openSimINI, "BSTestRegion", regionExtent); | ||
89 | |||
90 | BSScene bsScene = pScene as BSScene; | ||
91 | |||
92 | // Since the asset requestor is not initialized, any mesh or sculptie will be a cube. | ||
93 | // In the future, add a fake asset fetcher to get meshes and sculpts. | ||
94 | // bsScene.RequestAssetMethod = ???; | ||
95 | |||
96 | return bsScene; | ||
97 | } | ||
98 | |||
99 | } | ||
100 | } | ||
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs new file mode 100644 index 0000000..5a5de11 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs | |||
@@ -0,0 +1,205 @@ | |||
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.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using NUnit.Framework; | ||
34 | using log4net; | ||
35 | |||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Physics.BulletSPlugin; | ||
38 | using OpenSim.Region.Physics.Manager; | ||
39 | using OpenSim.Tests.Common; | ||
40 | |||
41 | using OpenMetaverse; | ||
42 | |||
43 | namespace OpenSim.Region.Physics.BulletSPlugin.Tests | ||
44 | { | ||
45 | [TestFixture] | ||
46 | public class HullCreation : OpenSimTestCase | ||
47 | { | ||
48 | // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 | ||
49 | // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 | ||
50 | |||
51 | BSScene PhysicsScene { get; set; } | ||
52 | Vector3 ObjectInitPosition; | ||
53 | |||
54 | [TestFixtureSetUp] | ||
55 | public void Init() | ||
56 | { | ||
57 | |||
58 | } | ||
59 | |||
60 | [TestFixtureTearDown] | ||
61 | public void TearDown() | ||
62 | { | ||
63 | if (PhysicsScene != null) | ||
64 | { | ||
65 | // The Dispose() will also free any physical objects in the scene | ||
66 | PhysicsScene.Dispose(); | ||
67 | PhysicsScene = null; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | [TestCase(7, 2, 5f, 5f, 32, 0f)] /* default hull parameters */ | ||
72 | public void GeomHullConvexDecomp( int maxDepthSplit, | ||
73 | int maxDepthSplitForSimpleShapes, | ||
74 | float concavityThresholdPercent, | ||
75 | float volumeConservationThresholdPercent, | ||
76 | int maxVertices, | ||
77 | float maxSkinWidth) | ||
78 | { | ||
79 | // Setup the physics engine to use the C# version of convex decomp | ||
80 | Dictionary<string, string> engineParams = new Dictionary<string, string>(); | ||
81 | engineParams.Add("MeshSculptedPrim", "true"); // ShouldMeshSculptedPrim | ||
82 | engineParams.Add("ForceSimplePrimMeshing", "false"); // ShouldForceSimplePrimMeshing | ||
83 | engineParams.Add("UseHullsForPhysicalObjects", "true"); // ShouldUseHullsForPhysicalObjects | ||
84 | engineParams.Add("ShouldRemoveZeroWidthTriangles", "true"); | ||
85 | engineParams.Add("ShouldUseBulletHACD", "false"); | ||
86 | engineParams.Add("ShouldUseSingleConvexHullForPrims", "true"); | ||
87 | engineParams.Add("ShouldUseGImpactShapeForPrims", "false"); | ||
88 | engineParams.Add("ShouldUseAssetHulls", "true"); | ||
89 | |||
90 | engineParams.Add("CSHullMaxDepthSplit", maxDepthSplit.ToString()); | ||
91 | engineParams.Add("CSHullMaxDepthSplitForSimpleShapes", maxDepthSplitForSimpleShapes.ToString()); | ||
92 | engineParams.Add("CSHullConcavityThresholdPercent", concavityThresholdPercent.ToString()); | ||
93 | engineParams.Add("CSHullVolumeConservationThresholdPercent", volumeConservationThresholdPercent.ToString()); | ||
94 | engineParams.Add("CSHullMaxVertices", maxVertices.ToString()); | ||
95 | engineParams.Add("CSHullMaxSkinWidth", maxSkinWidth.ToString()); | ||
96 | |||
97 | PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); | ||
98 | |||
99 | PrimitiveBaseShape pbs; | ||
100 | Vector3 pos; | ||
101 | Vector3 size; | ||
102 | Quaternion rot; | ||
103 | bool isPhys; | ||
104 | |||
105 | // Cylinder | ||
106 | pbs = PrimitiveBaseShape.CreateCylinder(); | ||
107 | pos = new Vector3(100.0f, 100.0f, 0f); | ||
108 | pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; | ||
109 | ObjectInitPosition = pos; | ||
110 | size = new Vector3(2f, 2f, 2f); | ||
111 | pbs.Scale = size; | ||
112 | rot = Quaternion.Identity; | ||
113 | isPhys = true; | ||
114 | uint cylinderLocalID = 123; | ||
115 | PhysicsScene.AddPrimShape("testCylinder", pbs, pos, size, rot, isPhys, cylinderLocalID); | ||
116 | BSPrim primTypeCylinder = (BSPrim)PhysicsScene.PhysObjects[cylinderLocalID]; | ||
117 | |||
118 | // Hollow Cylinder | ||
119 | pbs = PrimitiveBaseShape.CreateCylinder(); | ||
120 | pbs.ProfileHollow = (ushort)(0.70f * 50000); | ||
121 | pos = new Vector3(110.0f, 110.0f, 0f); | ||
122 | pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; | ||
123 | ObjectInitPosition = pos; | ||
124 | size = new Vector3(2f, 2f, 2f); | ||
125 | pbs.Scale = size; | ||
126 | rot = Quaternion.Identity; | ||
127 | isPhys = true; | ||
128 | uint hollowCylinderLocalID = 124; | ||
129 | PhysicsScene.AddPrimShape("testHollowCylinder", pbs, pos, size, rot, isPhys, hollowCylinderLocalID); | ||
130 | BSPrim primTypeHollowCylinder = (BSPrim)PhysicsScene.PhysObjects[hollowCylinderLocalID]; | ||
131 | |||
132 | // Torus | ||
133 | // ProfileCurve = Circle, PathCurve = Curve1 | ||
134 | pbs = PrimitiveBaseShape.CreateSphere(); | ||
135 | pbs.ProfileShape = (byte)ProfileShape.Circle; | ||
136 | pbs.PathCurve = (byte)Extrusion.Curve1; | ||
137 | pbs.PathScaleX = 100; // default hollow info as set in the viewer | ||
138 | pbs.PathScaleY = (int)(.25f / 0.01f) + 200; | ||
139 | pos = new Vector3(120.0f, 120.0f, 0f); | ||
140 | pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; | ||
141 | ObjectInitPosition = pos; | ||
142 | size = new Vector3(2f, 4f, 4f); | ||
143 | pbs.Scale = size; | ||
144 | rot = Quaternion.Identity; | ||
145 | isPhys = true; | ||
146 | uint torusLocalID = 125; | ||
147 | PhysicsScene.AddPrimShape("testTorus", pbs, pos, size, rot, isPhys, torusLocalID); | ||
148 | BSPrim primTypeTorus = (BSPrim)PhysicsScene.PhysObjects[torusLocalID]; | ||
149 | |||
150 | // The actual prim shape creation happens at taint time | ||
151 | PhysicsScene.ProcessTaints(); | ||
152 | |||
153 | // Check out the created hull shapes and report their characteristics | ||
154 | ReportShapeGeom(primTypeCylinder); | ||
155 | ReportShapeGeom(primTypeHollowCylinder); | ||
156 | ReportShapeGeom(primTypeTorus); | ||
157 | } | ||
158 | |||
159 | [TestCase] | ||
160 | public void GeomHullBulletHACD() | ||
161 | { | ||
162 | // Cylinder | ||
163 | // Hollow Cylinder | ||
164 | // Torus | ||
165 | } | ||
166 | |||
167 | private void ReportShapeGeom(BSPrim prim) | ||
168 | { | ||
169 | if (prim != null) | ||
170 | { | ||
171 | if (prim.PhysShape.HasPhysicalShape) | ||
172 | { | ||
173 | BSShape physShape = prim.PhysShape; | ||
174 | string shapeType = physShape.GetType().ToString(); | ||
175 | switch (shapeType) | ||
176 | { | ||
177 | case "OpenSim.Region.Physics.BulletSPlugin.BSShapeNative": | ||
178 | BSShapeNative nShape = physShape as BSShapeNative; | ||
179 | prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); | ||
180 | break; | ||
181 | case "OpenSim.Region.Physics.BulletSPlugin.BSShapeMesh": | ||
182 | BSShapeMesh mShape = physShape as BSShapeMesh; | ||
183 | prim.PhysScene.DetailLog("{0}, mesh, shapeInfo={1}", prim.Name, mShape.shapeInfo); | ||
184 | break; | ||
185 | case "OpenSim.Region.Physics.BulletSPlugin.BSShapeHull": | ||
186 | // BSShapeHull hShape = physShape as BSShapeHull; | ||
187 | // prim.PhysScene.DetailLog("{0}, hull, shapeInfo={1}", prim.Name, hShape.shapeInfo); | ||
188 | break; | ||
189 | case "OpenSim.Region.Physics.BulletSPlugin.BSShapeConvexHull": | ||
190 | BSShapeConvexHull chShape = physShape as BSShapeConvexHull; | ||
191 | prim.PhysScene.DetailLog("{0}, convexHull, shapeInfo={1}", prim.Name, chShape.shapeInfo); | ||
192 | break; | ||
193 | case "OpenSim.Region.Physics.BulletSPlugin.BSShapeCompound": | ||
194 | BSShapeCompound cShape = physShape as BSShapeCompound; | ||
195 | prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); | ||
196 | break; | ||
197 | default: | ||
198 | prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); | ||
199 | break; | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | } \ No newline at end of file | ||